---
title: "Ask for a form to upload a file the policy asks for as evidence"
method: POST
path: "/evidence-attachments"
tags: ["evidence"]
---

# Ask for a form to upload a file the policy asks for as evidence

`POST /evidence-attachments`

## Request

- Base URL: `https://api.catena.com/v1/agent-api`
- URL: `https://api.catena.com/v1/agent-api/evidence-attachments`
- Auth: HTTP bearer

## Headers

- `Idempotency-Key` string, required

## Request body

- object
  - `contentType` string, required: The file's media type: image/png, image/jpeg or image/webp
  - `sizeBytes` number, required: The file's length in bytes
  - `sha256Hex` string, required: The SHA-256 digest of the file, in lowercase hex
  - `filename` string: A name to show people looking at the evidence; never trusted

## Response `200`

The attachment this key already names, with a new form while it still awaits the file

- object
  - `attachment` object, required
    - `id` string, required
    - `state` string, required: awaiting_upload: post the file with the upload form. processing: Catena is scanning and checking it. ready: an intent can use it. rejected: the file was refused, for outcomeReason. failed: ask for the upload again and send the file again
    - `outcomeReason` string, nullable, required: Why a rejected or failed attachment ended, such as malware, hash_mismatch, animated or not_uploaded; null otherwise
    - `contentType` string, required: The declared media type, and once ready the one verified from the bytes
    - `sizeBytes` number, required
    - `sha256Hex` string, required
    - `filename` string, nullable, required
    - `expiresAt` string, required: When the attachment is removed unless an intent has used it first
    - `intentId` string, nullable, required: The intent that used the attachment as evidence; null until one does
  - `upload` object, nullable, required: POST the file to url as multipart/form-data: every field as given, then the file last, named file
    - `url` string, required
    - `fields` object, required
    - `expiresAt` string, required

## Other responses

- `201`: A new attachment, awaiting the file. Post it with `upload` before `upload.expiresAt`, then read the attachment until it is ready, rejected or failed
- `400`: The request is malformed, has no Idempotency-Key (`idempotency_key_required`), or declares a media type or digest Catena does not accept
- `403`: The agent's policy asks for no file for anything it is granted (`evidence_attachments_not_accepted`), or the agent has no active policy (no `code`)
- `409`: The key names an attachment that declared another file (`evidence_upload_key_reused`), its upload can no longer complete (`upload_closed`), or the agent is staging as many attachments or bytes as it may (`evidence_staging_quota_exceeded`, with both limits in `details` and, in `details.availableAt`, Catena's estimate of when enough room frees up with nothing more from the agent; a request sent then can be refused again, with a later estimate). Also refused when the agent's policy cannot be read (`policy_unreadable`) until an admin saves its full configuration or, for a temporary override, revokes it and grants a new one; nothing changed, and GET /policy shows it with `invalidReason`
- `413`: The declared file is larger than Catena accepts
- `503`: Evidence uploads are unavailable right now (`evidence_uploads_unavailable`)

---

[API](https://skmtc.dev/catena/apis/catena-agent-api.md) - [All operations](https://skmtc.dev/catena/apis/catena-agent-api/llms.txt) - [OpenAPI document](https://skmtc.dev/catena/apis/catena-agent-api/revisions/9b72e32d21f1?raw)
