# Artifacts (/api-v2/artifacts)



An artifact is an immutable content unit: a system instruction, a tool definition, a schema, a policy, a document, a retrieval chunk. Once created it never changes, so there is deliberately no update endpoint. The public id is opaque (`art_...`) and never a content hash. See [artifacts](/concepts/artifacts) for the object model.

All requests require a bearer API key. See [authentication](/api-reference/authentication).

## Create an artifact [#create-an-artifact]

`POST /v2/artifacts`

<ParamField body="artifact_type" type="string">
  One of `text_context`, `tool_bundle_source`, `response_schema`, `document`, `retrieval_chunk`, `policy`, `checkpoint`, `compaction_summary`, `binary_attachment`.
</ParamField>

<ParamField body="content" type="string">
  The artifact content. Must not be empty.
</ParamField>

<ParamField body="content_media_type" type="string" default="text/plain">
  IANA media type describing `content`.
</ParamField>

<ParamField body="retention_class" type="string" default="standard">
  One of `ephemeral`, `standard`, `extended`. See [retention and purge](/concepts/retention-and-purge).
</ParamField>

<ParamField body="metadata" type="object">
  Arbitrary JSON you attach for your own bookkeeping. Stored verbatim.
</ParamField>

```bash
curl https://api.zumik.ai/v2/artifacts \
  -H "Authorization: Bearer $ZUMIK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "artifact_type": "policy",
    "content": "Always run the linter before committing.",
    "retention_class": "standard"
  }'
```

```python
from zumik import Zumik

zk = Zumik()
artifact = zk.artifacts.create(
    artifact_type="policy",
    content="Always run the linter before committing.",
)
```

```json
{
  "id": "art_01jy7n3q8v6kzr4w2m9bd5xpfh",
  "object": "artifact",
  "artifact_type": "policy",
  "project_id": "prj_01jy7n0a4c8m2t6v9q3wrxk7bd",
  "content_media_type": "text/plain",
  "created_at": "2026-06-15T16:04:10Z",
  "retention_class": "standard",
  "metadata": {}
}
```

<ResponseField name="id" type="string">
  Opaque artifact id, prefixed `art_`.
</ResponseField>

<ResponseField name="object" type="string">
  Always `artifact`.
</ResponseField>

<ResponseField name="artifact_type" type="string">
  The artifact type, echoed back.
</ResponseField>

<ResponseField name="project_id" type="string">
  The owning project, prefixed `prj_`.
</ResponseField>

<ResponseField name="content_media_type" type="string">
  The media type stored for `content`.
</ResponseField>

<ResponseField name="created_at" type="string">
  RFC 3339 creation timestamp.
</ResponseField>

<ResponseField name="retention_class" type="string">
  The retention class applied.
</ResponseField>

<ResponseField name="metadata" type="object">
  The metadata you supplied.
</ResponseField>

The raw `content` is never returned on retrieve; only the artifact's identity and metadata are. Store your own copy if you need the text back.

## Retrieve an artifact [#retrieve-an-artifact]

`GET /v2/artifacts/{artifact_id}`

<ParamField path="artifact_id" type="string">
  The artifact id to fetch.
</ParamField>

```bash
curl https://api.zumik.ai/v2/artifacts/art_01jy7n3q8v6kzr4w2m9bd5xpfh \
  -H "Authorization: Bearer $ZUMIK_API_KEY"
```

Returns the same artifact object as create. An id that belongs to another project returns `404` rather than `403`, so existence never leaks across a tenant boundary.

## Delete an artifact [#delete-an-artifact]

`DELETE /v2/artifacts/{artifact_id}`

Delete revokes access immediately. For an auditable, evidence-backed teardown of retained representations, use a [purge job](/api-v2/purge-jobs) instead.

<ParamField path="artifact_id" type="string">
  The artifact id to delete.
</ParamField>

```bash
curl -X DELETE https://api.zumik.ai/v2/artifacts/art_01jy7n3q8v6kzr4w2m9bd5xpfh \
  -H "Authorization: Bearer $ZUMIK_API_KEY"
```

```json
{
  "id": "art_01jy7n3q8v6kzr4w2m9bd5xpfh",
  "object": "artifact.deleted",
  "deleted": true
}
```

<ResponseField name="id" type="string">
  The deleted artifact id.
</ResponseField>

<ResponseField name="object" type="string">
  Always `artifact.deleted`.
</ResponseField>

<ResponseField name="deleted" type="boolean">
  `true` when the artifact was removed.
</ResponseField>

## Errors [#errors]

| Status | Code                    | When                                         |
| ------ | ----------------------- | -------------------------------------------- |
| 400    | `invalid_request_error` | `content` is empty.                          |
| 401    | `invalid_api_key`       | Missing or invalid API key.                  |
| 404    | `invalid_request_error` | The artifact does not exist in this project. |

See the full table on [errors](/api-reference/errors). Mutating requests may carry an [idempotency key](/api-reference/idempotency).
