---
title: "Initiate Attachment Upload"
method: POST
path: "/attachments"
---

# Initiate Attachment Upload

`POST /attachments`

Initiates (or deduplicates) an upload of a file attached to a session. If the exact content is already stored for this (session ID, file path), the response has `alreadyExists: true` and no upload is needed. Otherwise, PUT the file bytes to the returned `uploadUrl`, then call the commit endpoint. Re-initiating an existing (session ID, file path) with new content updates the attachment in place on commit.

## Request body

- object
  - `sessionId` string, required — The session ID the attachment belongs to. Matches the `session.id` emitted on OTel spans, which is how attachments are joined to traces and records.
  - `filePath` string, required — The logical file path of the attachment (e.g. the path the agent wrote on disk). Together with the session ID it identifies the attachment: re-uploading the same path in the same session updates the existing attachment in place.
  - `sha256` string, required — Lowercase hex SHA-256 of the file content.
  - `sizeBytes` integer, required — Size of the file in bytes.
  - `contentType` string, required — MIME type of the file.
  - `filename` string — Display filename. Defaults to none.
  - `metadata` object — Arbitrary metadata to store with the attachment.

## Response `201`

Upload initiated (or content already stored). If `alreadyExists` is false, PUT the bytes to `uploadUrl` and then commit.

- object
  - `id` string, uuid, required — The ID of the Attachment.
  - `alreadyExists` boolean, required — True if this exact content is already stored for this (session, file path) — no upload is needed and no upload URL is returned.
  - `uploadUrl` string, nullable, required — Signed URL to PUT the file bytes to. Null when `alreadyExists` is true.
  - `uploadMethod` 'PUT' | 'null', nullable, required — HTTP method to use with `uploadUrl`.
  - `expiresAt` string, nullable, required — ISO 8601 expiry of `uploadUrl`.

## Other responses

- `401` — Error indicating that the request is not authenticated.
- `500` — An internal service error indicating an issue with the Scorecard service.

---

[API](https://skmtc.dev/scorecard-ai/apis/scorecard-api.md) · [All operations](https://skmtc.dev/scorecard-ai/apis/scorecard-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/scorecard-ai/scorecard-api/revisions/121aaa257802/schema)
