---
title: "Upload managed raw bytes for a registered document."
method: PUT
path: "/v1/documents/{id}/raw"
tags: ["Documents"]
---

# Upload managed raw bytes for a registered document.

`PUT /v1/documents/{id}/raw`

Stores the request body as the document's managed blob via the configured `RawContentStore` adapter (`local_fs` or `s3`), and promotes the document row to `storage_mode='managed_blob'` / `raw_storage_status='blob_stored'`. Idempotent on byte-identical input under the same document. Different bytes against an already-stored managed blob return 409 because the managed slot is immutable per row to avoid orphaning the prior blob. Returns 503 when the deployment runs `rawStorageMode='pointer_only'`.

## Path parameters

- `id` string, uuid, required

## Query parameters

- `user_id` string, required
- `content_type` string

## Response `200`

Upload result with storage URI + content hash + size.

- object — Managed-blob upload result. The document row is now `storage_mode='managed_blob'` with `raw_storage_status` set to `'blob_stored'` (immediate providers — local_fs, s3), `'blob_pending'` (eventual providers awaiting the reconciler), or `'blob_available'` (gateway-confirmed retrievable on Filecoin). `content_hash` is the SHA-256 of the PLAINTEXT bytes (distinct from `indexed_content_hash` and from the encoded-byte hash the codec writes under `raw_storage_metadata.codec`, which is internal). `raw_storage_metadata` is the public allowlist (codec name+version + Synapse filecoin allowlist with flattened copy_count/provider_ids/copy_statuses — internal sidecars stripped). `delete_semantics` advertises what AtomicMemory's DELETE call will do at the provider boundary for this row. `idempotent_skip: true` when the same bytes were already attached to this document.
  - `content_hash` string, required
  - `delete_semantics` 'delete' | 'unpin' | 'tombstone' | 'null', nullable, required — What AtomicMemory's DELETE call does at the provider boundary for this row's storage_provider. `'delete'` = adapter issues the provider's removal operation; `'unpin'` = removes AtomicMemory's pin but the provider's other peers may continue to serve; `'tombstone'` = AtomicMemory stops managing the bytes but the decentralized network may still serve. `null` for pointer-only rows or providers not registered for cleanup.
  - `document_id` string, required
  - `idempotent_skip` boolean, required
  - `raw_storage_metadata` object, required — Public-facing raw_storage_metadata. STRICTLY allowlisted: codec emits only name+version (AES-GCM internals never reach the wire); filecoin emits public fields (ipfs_cid, piece_cid, copy_count, provider_ids, copy_statuses) — `ipfs_cid` is an optional CIDv1 IPFS / CAR-root identity hint populated by drivers that derive one alongside the PieceCID; the canonical storage URI stays `filecoin://piece/<piece_cid>` regardless. The internal structured copies[{provider_id,status}] shape is flattened at the formatter; upload_result and other internal sidecars are NEVER emitted. The schema is deny-by-default (`.strict()`) at every level — a formatter regression that lets unknown keys through fails response-shape validation.
    - `codec` object
      - `name` 'none' | 'aes_gcm', required
      - `version` number, required
    - `filecoin` object
      - `copy_count` integer
      - `copy_statuses` string[]
      - `ipfs_cid` string
      - `piece_cid` string
      - `provider_ids` string[]
  - `raw_storage_status` 'blob_stored' | 'blob_pending' | 'blob_available', required
  - `size_bytes` number, required
  - `storage_mode` 'managed_blob', required
  - `storage_provider` string, required
  - `storage_uri` string, required

## Other responses

- `400` — Input validation error
- `404` — Document not found
- `409` — Conflict: the document already has a managed blob with a different content_hash. Register a fresh document for the new bytes — the existing blob is not overwritten.
- `500` — Internal server error
- `502` — Upstream AI provider returned an unrecoverable failure (auth, non-retryable 4xx).
- `503` — Upstream AI provider is rate-limited, quota-exhausted, or returned 5xx; consult `retryable`.

---

[API](https://skmtc.net/atomicstrata/apis/atomicmemory-http-api.md) · [All operations](https://skmtc.net/atomicstrata/apis/atomicmemory-http-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/atomicstrata/atomicmemory-http-api/versions/d501daa39bb2/schema)
