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

# Assets REST API reference

> The routes, wire fields, response states, and concurrency rules shared by every official Assets SDK.

<Tip>
  **Live.** This area is documented as current, user-reliable behavior.
</Tip>

## Goal

Call Assets directly when an SDK does not cover your runtime, or use this page to understand what an SDK request sends over the wire.

## Prerequisites

* A StackShift API key
* A UUID asset, bucket, session, or job ID when a route requires one

## Workflow

<Steps>
  <Step>
    Send `Authorization: Bearer <api-key>` to the control-plane API.
  </Step>

  <Step>
    Use the `/api/v1` base URL for account and asset management requests.
  </Step>

  <Step>
    Use snake\_case JSON names such as `cache_control`, `max_downloads`, and `checksum_sha256`.
  </Step>

  <Step>
    Read the `data` field from the success envelope and preserve `revision`/`ETag` values for later mutations.
  </Step>

  <Step>
    Poll the returned job, migration, or text-extraction resource instead of treating `202 Accepted` as completion.
  </Step>
</Steps>

## Authentication and response envelope

The protected Assets routes are account-scoped. The API key selects the account’s default Assets space; clients do not send a project ID or an internal asset-space ID. Use the narrowest available Assets scope for the operation: `assets:read`, `assets:write`, `assets:process`, `assets:generate`, `assets:publish`, or `assets:admin`.

```bash theme={null}
curl -H "Authorization: Bearer $STACKSHIFT_API_KEY" \
  -H "Accept: application/json" \
  https://api.stackshift.cloud/api/v1/assets
```

```json theme={null}
{
  "success": true,
  "data": {
    "assets": [],
    "total": 0,
    "next_cursor": ""
  }
}
```

## Core routes

* `POST /api/v1/assets/upload` accepts a multipart `file` plus `bucket`, `key`, `folder`, `visibility`, `cache_control`, and JSON `metadata`.
* `GET /api/v1/assets` lists assets. Filters include `bucket`, `prefix`, `visibility`, `query`, `tag`, `mime_type`, `type`, `folder`, `checksum`, `status`, `scan_status`, `replication_status`, `moderation_status`, and `quarantine_status`. Sorting accepts `created_at`, `updated_at`, `size`, `key`, `original_name`, or `mime_type` with `direction=asc|desc`.
* `GET /api/v1/assets/{assetID}` returns one asset. `PUT /api/v1/assets/{assetID}/replace` replaces its bytes while preserving the logical asset ID.
* `PATCH /api/v1/assets/{assetID}` updates bucket, key, original name, cache control, or visibility. `PUT /api/v1/assets/{assetID}/tags` replaces the tag set. `PATCH /api/v1/assets/{assetID}/metadata` merges supplied JSON keys into metadata.
* `POST /api/v1/assets/{assetID}/signed-url` creates a private download URL. The JSON fields are `expires_in` and optional `max_downloads`.
* `DELETE /api/v1/assets/{assetID}` starts a revision-checked asynchronous delete. `POST /api/v1/assets/{assetID}/purge` requests cache invalidation for the asset.

## Account controls and DAM routes

* Buckets: `GET/POST /api/v1/assets/buckets`, then `PUT/DELETE /api/v1/assets/buckets/{bucketID}` with the bucket revision. Bucket fields include default visibility, cache control, versioning, retention, byte/MIME limits, CORS/allowed origins, home region, replication policy, lifecycle policy, and an optional custom domain.
* Content policy: `GET/PUT /api/v1/assets/policy` with `allowed_mime_types`, `max_image_bytes`, `max_video_bytes`, `max_other_bytes`, and `require_scan`.
* Transformations: `POST/GET /api/v1/assets/transformations` and `DELETE /api/v1/assets/transformations/{name}`. The POST body accepts legacy fields or a typed v2 definition plus eager policy. `POST /assets/{assetID}/transforms` materializes a definition/preset; `GET /derivatives` lists persisted outputs.
* Lifecycle: `POST/GET /api/v1/assets/lifecycle-rules` and `DELETE /api/v1/assets/lifecycle-rules/{ruleID}`. A rule has `name`, optional `prefix`, `action=delete|expire_versions`, `age_days`, and `enabled`.
* Custom domains: `POST/GET /api/v1/assets/domains`, `POST /api/v1/assets/domains/{domainID}/verify`, and `DELETE /api/v1/assets/domains/{domainID}`.
* Operations: `GET /api/v1/assets/analytics`, `/summary`, and `/events` expose delivery/transform/AI usage, grouped totals, duplicate groups, and the audit stream.
* Webhooks: `POST/GET/DELETE /api/v1/assets/webhooks`, `GET /api/v1/assets/webhooks/{webhookID}/deliveries`, and `POST /api/v1/assets/webhook-deliveries/{deliveryID}/retry`. The create response includes the signing secret once.
* DAM organization: `GET/POST/PUT/DELETE /api/v1/assets/collections` and `GET/POST/PUT/DELETE /api/v1/assets/saved-searches`; collections store asset IDs and saved searches store a filter object.
* Bulk: `POST /api/v1/assets/bulk` accepts revisioned items for `delete`, `visibility`, or `add_tags` and returns a durable job submission.

## AI, versions, and branches

* AI policy/config: `GET/PUT /api/v1/assets/ai/config`; the update requires `If-Match` and accepts `enabled_actions` plus `monthly_spend_cap_micros`.
* AI data and actions: `GET /api/v1/assets/{assetID}/ai`, `POST /ai/analyze`, `POST /moderation`, `GET/POST /transcript`, `POST /smart-crop`, and `POST /background-remove`.
* Net-new generation: `POST /api/v1/assets/generations` requires `assets:generate` plus `Idempotency-Key`, creates private images, and returns a durable job.
* Version history: `GET /api/v1/assets/{assetID}/versions`, `POST /versions/{versionID}/restore`, `POST /branches`, and `POST /branches/{branch}/promote`.
* Delivery helpers: public/current, private/current, version, branch, named-transform, signed-transform, and video paths are served by the CDN rather than the control-plane JSON API.

## Connections, storage, migrations, widget capabilities, and OCR

* Connections: `POST/GET /api/v1/assets/connections`, `GET/PATCH/DELETE /api/v1/assets/connections/{connectionID}`, and `POST /verify`. Secret values are accepted only on create/update and are never returned.
* S2 and storage: `GET/POST /api/v1/assets/s2-buckets`, `PUT /api/v1/assets/buckets/{bucketID}/storage`, and `POST /api/v1/assets/buckets/{bucketID}/relocations`. Storage updates require the current bucket revision.
* Migrations: `POST/GET /api/v1/assets/migrations`, `GET /{migrationID}`, `POST /cancel`, `POST /items/{itemID}/retry`, and raw JSON/CSV `GET /report` downloads.
* OCR: `POST/GET /api/v1/assets/{assetID}/text-extraction` and `POST /api/v1/assets/text-extractions/{extractionID}/retry`.
* Widget authorization: `POST /api/v1/assets/upload-capabilities` returns one short-lived capability token. Capability-only browser traffic uses `/assets/widget`, outside the authenticated `/api/v1` management base.
* See the platform operations guide for exact request fields, status codes, token scopes, SDK clients, CLI commands, events, and recovery behavior.

## Workflows, automation, and MCP

* Workflow catalog and drafts: `GET /assets/workflows/catalog`, `GET/POST /assets/workflows`, `GET /assets/workflows/{workflowId}`, `PUT /draft`, and `POST /validate`.
* Immutable operation: `POST /publish`, `POST /activate`, `GET /versions`, `POST /run`, and workflow-scoped `GET /runs`. Global run detail/cancel/retry is under `/assets/workflows/runs/{runId}`.
* Governance: `GET /assets/workflows/approvals`, approve/reject endpoints, restricted HTTP connections and credential rotation, and active-workflow inbound-hook rotation.
* `GET /assets/automation` describes governed tools and recent audits. `/assets/mcp` is the stateless Streamable HTTP MCP transport; each tool enforces its declared scope.
* The public signed receiver is `POST /api/v1/assets/workflow-hooks/{token}` with timestamp, delivery ID, and HMAC signature headers.

## Upload sessions

* `POST /api/v1/assets/upload-sessions` creates either a single PUT session or a chunked session. Set `mode=chunked`, `file_name`, `file_size`, `mime_type`, optional `checksum_sha256`, and optional `part_size` for resumable uploads.
* `POST /api/v1/assets/upload-url` is the legacy-compatible alias for creating the same session response. The current SDK uses `/upload-sessions`; the alias also accepts legacy camelCase field names for older clients.
* The response contains `upload_session_id`, `session_id` for chunked sessions, the signed PUT `url`, `expires_at`, `max_bytes`, and `part_size`.
* PUT a single file to the signed URL. For a chunked session, PUT each part to `{upload_url}/parts/{part_number}` with an `X-Content-SHA256` header, then call `POST /api/v1/assets/upload-sessions/{sessionID}/complete`.
* `GET /api/v1/assets/upload-sessions/{sessionID}` returns the session and received parts so a client can resume. `DELETE` cancels the session and cleans up its temporary parts.
* Send `Idempotency-Key` when creating a session. Reusing the key with different canonical request content returns a conflict instead of creating a second session.

## Concurrency and idempotency

* Asset and bucket mutations require `If-Match: "<revision>"`. The current response includes an `ETag` with the same revision. A stale or missing revision is rejected so an older dashboard cannot overwrite a newer edit.
* Upload, replace, delete, bulk, and AI job mutations accept `Idempotency-Key` where the SDK exposes one. A key with different request content returns `assets.idempotency_conflict`.
* List cursors are opaque and bound to their sort and direction. Keep using the returned `next_cursor`; do not manufacture or decode cursors.

## Asynchronous jobs and states

* AI actions, bulk actions, and physical deletion return `202 Accepted` with `job_id`, `status`, and `status_url`. Poll `GET /api/v1/assets/jobs/{jobID}` and cancel with `POST /api/v1/assets/jobs/{jobID}/cancel` when supported.
* A newly uploaded asset may be `processing` before it is `ready`. `quarantined` and `failed` assets have no deliverable public URL. A delete moves through `deleting` before the physical replicas are removed.
* AI requests can be rejected when the action is not enabled for the account, the monthly spend cap is exhausted, or the configured model has not passed the evaluation gate.

## Delivery URL shapes

* Current public version: `https://cdn.stackshift.cloud/assets/{assetID}/versions/{versionID}/{filename}`.
* Private signed version: `https://cdn.stackshift.cloud/private/assets/{assetID}/versions/{versionID}/{filename}?token=...`.
* Named transform: `https://cdn.stackshift.cloud/t/{preset}/assets/{assetID}`.
* Signed transform: `https://cdn.stackshift.cloud/assets/{assetID}/tr/{spec}/{filename}?exp=...&sig=...`.
* Video output: `.../assets/{assetID}/video/{kind}/{profile}` for `hls`, `poster`, `thumbnail`, or `mp4`; add the private token query parameter for a private output.
* The SDK URL helpers are preferred because they use the configured CDN base URL and escape IDs, names, specs, and filenames correctly.

## Common error codes

* `401` means the API key or session is missing or invalid. `404` means the asset, bucket, job, or delivery target is not visible in the account.
* `409` is used for duplicate keys, idempotency conflicts, or an idempotent operation still in progress.
* `428` means a required `If-Match` header is missing; `412` means the supplied revision is stale and does not match the current revision.
* `422` indicates a checksum mismatch. Content-policy and request validation failures use `400`; `402` can indicate an asset quota or AI spend cap has been reached.
* A public delivery `404` is also expected for an asset that is not ready, quarantined, deleted, or missing an available replica. Do not retry it as if it were a transient CDN failure without checking the asset state.

## Expected result

<Check>
  You can map any Assets SDK method to its REST route and handle successful, asynchronous, conflicting, and quarantined responses correctly.
</Check>

## Related guides

<CardGroup cols={2}>
  <Card title="StackShift Assets" href="/assets/overview">
    A grounded guide to Assets storage, uploads, delivery, imports, BYOB and S2, transformations, OCR, media processing, AI jobs, and DAM controls.
  </Card>

  <Card title="Assets SDK quick start" href="/assets/sdk-quick-start">
    Install the official SDKs, upload a first asset, and handle the readiness state before you publish its URL.
  </Card>

  <Card title="Deterministic image, video, and audio transforms" href="/assets/deterministic-media-transforms">
    Define ordered v2 transforms for images, video renditions, audio extraction, and timestamp thumbnails; store eager presets or materialize durable derivatives.
  </Card>

  <Card title="Media Workflows visual builder and API" href="/assets/media-workflows">
    Author editable templates or blank typed DAGs that coordinate asset gates, native StackShift services, bounded Stackie reasoning, and approved external integrations.
  </Card>
</CardGroup>
