> ## Documentation Index
> Fetch the complete documentation index at: https://docs.batchrelay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Managed assets

> Copy external images into private temporary storage or reuse an existing managed asset.

`POST /v1/assets/ingest` creates or resolves one opaque managed asset for render
and managed attachment workflows. It requires `print_orders:write` and an
`Idempotency-Key` containing 1–200 characters.

The returned `asset_id` can be used directly in a public print-order asset or a
template image slot. A print-order asset also accepts an external HTTPS `url`;
Batch Relay copies that source during quote creation and freezes the resulting
managed asset with the quote.

## Choose exactly one source

The request must contain exactly one of `url` or `asset_id`.

Use `url` to copy an externally routable HTTPS image into Batch Relay's private
fulfillment storage:

```bash theme={null}
curl -X POST https://batchrelay-api-staging.up.railway.app/v1/assets/ingest \
  -H 'Authorization: Bearer br_test_example' \
  -H 'Idempotency-Key: asset-weekend-001' \
  -H 'Content-Type: application/json' \
  -d '{
    "url": "https://assets.example.com/source/player.jpg",
    "original_filename": "player.jpg"
  }'
```

Batch Relay downloads the complete file with network-safety checks, validates
the image, calculates its SHA-256 digest and dimensions, and writes an immutable
content-addressed object to private fulfillment R2. The original URL is neither
retained as the fulfillment URL nor exposed to the provider. The public limits
are 16 MiB, 100 million pixels, and JPEG, PNG, or TIFF input.

Use `asset_id` to resolve a ready, authorized managed asset without copying its
bytes:

```json theme={null}
{
  "asset_id": "bra_0123456789abcdef0123456789abcdef"
}
```

For a studio-owned API account, this reuse path can also resolve a finalized
same-studio platform image. Platform images remain in the studio-private bucket;
they are referenced in place and are not copied into fulfillment storage.
Cross-account and cross-studio IDs fail closed.

Supplying both sources or neither source returns `invalid_asset_source` (`422`).
Reusing an idempotency key with different request content returns
`idempotency_conflict` (`409`). A deployment without its managed registry or
private R2 configuration returns a managed-asset unavailable error (`503`).

## Response

The successful `201` response returns the stable `asset_id` plus immutable
metadata. `reused` is `true` when Batch Relay resolved an existing `asset_id` or
the content-addressed object already existed.

```json theme={null}
{
  "asset_id": "bra_0123456789abcdef0123456789abcdef",
  "storage_scope": "fulfillment",
  "byte_size": 842311,
  "content_type": "image/jpeg",
  "format": "jpeg",
  "pixel_width": 2000,
  "pixel_height": 2500,
  "sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  "original_filename": "player.jpg",
  "reused": false
}
```

Use this ID in an image slot for `POST /v1/templates/{template_id}/renders` or
as the source of a public print-order asset. Each print-order asset contains its
semantic `role` and exactly one of `url` or `asset_id`. Hosted renderer dispatch
is enabled on the staging API. Production availability remains independent and
must be verified before enabling a production workflow.

## Retention and reprints

Managed external assets are temporary:

* An unattached asset is scheduled for cleanup 28 days after its managed record
  is created.
* Once attached to an order, retention extends to the later of 28 days after
  order placement or 14 days after verified shipment.
* An open reprint hold removes the cleanup deadline. Closing the hold applies
  its explicit future extension and recalculates the latest deadline across all
  attachments.

Cleanup operates in bounded batches through short-lived claimed jobs. Before
deletion, Batch Relay rechecks the deadline and retention state; an open reprint
hold cancels authorization. Deletion is restricted to exact managed object-key
shapes under `fulfillment/api-ingested/sha256/` and
`fulfillment/rendered/<job>/<surface>/<sha256>.<format>`; it cannot delete a
studio object or enumerate a prefix.

Do not treat `asset_id` as permanent archival storage. After authorized cleanup,
re-ingest your retained source before a new render or attachment.
