> ## 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 platform API, SDK, CLI, and operations

> A complete interface and recovery reference for storage connections, S2, imports, relocation, OCR, browser capabilities, reports, scopes, events, billing, and durable worker behavior.

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

## Goal

Operate every Assets expansion surface through a supported interface and recover from provider, worker, checksum, credential, or OCR failures without losing access to asset bytes.

## Prerequisites

* A StackShift API token with the narrowest required Assets scope
* The current JavaScript SDK or StackShift CLI when not calling REST directly
* Access to Assets Operations in the dashboard for visual connection, migration, relocation, and OCR workflows

## Workflow

<Steps>
  <Step>
    Choose the narrowest token scope from the route matrix before creating automation.
  </Step>

  <Step>
    Use the nested JavaScript SDK clients for typed calls, the CLI for operator workflows, or the documented REST routes for another runtime.
  </Step>

  <Step>
    Treat migration, relocation, and OCR state records as authoritative; do not infer completion from request acceptance or worker logs.
  </Step>

  <Step>
    Use item reports, warning/error codes, events, and provider verification to identify the failing boundary.
  </Step>

  <Step>
    Restore access to the recorded backend first, then retry the smallest failed unit and confirm CDN origin health.
  </Step>
</Steps>

## Authentication, response rules, and scopes

Management routes use `https://api.stackshift.cloud/api/v1` and `Authorization: Bearer <token>`. Normal successful responses use the StackShift `success`/`data` envelope. Migration reports are raw `application/json` or `text/csv` downloads. Widget data-plane routes use `https://api.stackshift.cloud/assets/widget` with a one-time capability token and an exact HTTPS `Origin`; they do not accept a general Assets token.

* `assets:read`: list/get connections, S2 buckets, migrations and reports, text results, buckets, assets, usage, and events.
* `assets:write`: create browser upload capabilities and change bucket storage configuration. Existing upload and library-write routes also use this scope.
* `assets:process`: start/cancel migrations, start relocation, retry migration items, start/retry OCR, and invoke other transform/AI processing routes.
* `assets:generate`: create net-new private images through the governed generation job.
* `assets:publish`: publish/activate governed workflow versions and decide publication-bearing approvals.
* `assets:admin`: create/update/verify/delete provider connections, create an owned S2 bucket, and perform destructive or credential administration.
* An `assets:admin` token permits all Assets routes. Read methods are also permitted by `assets:write` and `assets:process`; prefer including `assets:read` explicitly when minting purpose-specific automation tokens.

## Connection and storage REST routes

* `POST /assets/connections` (`assets:admin`, 201): create a tenant-scoped external, S2, or Cloudinary connection.
* `GET /assets/connections` and `GET /assets/connections/{connectionID}` (`assets:read`, 200): return redacted configuration and verification state.
* `PATCH /assets/connections/{connectionID}` (`assets:admin`, 200): change display/configuration fields or replace a secret without returning it.
* `POST /assets/connections/{connectionID}/verify` (`assets:admin`, 200): perform the provider probe and persist the result.
* `DELETE /assets/connections/{connectionID}` (`assets:admin`, 200): revoke/delete only when no protected reference remains.
* `GET /assets/s2-buckets` (`assets:read`, 200) and `POST /assets/s2-buckets` (`assets:admin`, 201): list or create user-owned S2 buckets for Assets.
* `PUT /assets/buckets/{bucketID}/storage` (`assets:write`, 200): set `storage_mode`, backend reference, prefixes, `auto_extract_text`, and expected revision. Send the revision in `If-Match` or `expected_revision`.
* `POST /assets/buckets/{bucketID}/relocations` (`assets:process`, 202): create a relocation inventory with optional `dry_run`.

## Migration, OCR, and capability REST routes

* `POST /assets/migrations` (`assets:process`, 202): start `import` or `relocate` with source connection, destination bucket, prefix, conflict policy, and dry-run mode.
* `GET /assets/migrations?limit=N` and `GET /assets/migrations/{migrationID}` (`assets:read`, 200): read persisted summaries and progress.
* `POST /assets/migrations/{migrationID}/cancel` (`assets:process`, 200): request cooperative cancellation.
* `POST /assets/migrations/{migrationID}/items/{itemID}/retry` (`assets:process`, 202): requeue one terminal failed item.
* `GET /assets/migrations/{migrationID}/report?format=json|csv` (`assets:read`, 200): download the complete JSON report or CSV projection.
* `POST /assets/{assetID}/text-extraction` (`assets:process`, 202): start or link a cached extraction with `language` and `options`.
* `GET /assets/{assetID}/text-extraction` (`assets:read`, 200) and `POST /assets/text-extractions/{extractionID}/retry` (`assets:process`, 202): read or retry OCR.
* `POST /assets/upload-capabilities` (`assets:write`, 201): create the one-time browser capability. The token is returned only in this response.

## Capability-only widget routes

* `POST /assets/widget/sessions`: create one chunked session from the capability; request fields are `key`, `file_name`, `file_size`, `mime_type`, optional `checksum_sha256`, `part_size`, and `metadata`.
* `GET /assets/widget/sessions/current`: reconcile the capability-bound session and its received parts.
* `PUT /assets/widget/uploads/{sessionToken}/parts/{partNumber}`: stream one part with `X-Content-SHA256`.
* `POST /assets/widget/sessions/current/complete`: verify and commit the asset, then revoke the capability.
* `DELETE /assets/widget/sessions/current`: cancel temporary upload state and revoke the capability.
* `POST /assets/widget/remote-url`: ingest `{ url, key }` only when the capability explicitly permits remote URLs.
* CORS allows only the normalized origin carried by the request and the capability. Allowed headers are `Authorization`, `Content-Type`, and `X-Content-SHA256`; the exposed response header is `ETag`.

## JavaScript SDK clients

`StackShift.assets` keeps the existing upload, delivery, transform, DAM, video, and AI methods and adds typed platform and workflow clients. All names below map directly to documented REST routes.

* `assets.connections`: `create`, `list`, `get`, `update`, `verify`, and `delete`.
* `assets.storage`: `configure`, `listS2Buckets`, `createS2Bucket`, and `relocate`.
* `assets.migrations`: `start`, `list`, `get`, `cancel`, `retryItem`, `report`, and `downloadReport`. Use `downloadReport` for raw JSON/CSV `Blob` data.
* `assets.text`: `start`, `get`, and `retry`.
* `assets.uploadCapabilities`: `create` for trusted backend code only.
* `assets.workflows`: catalog, draft CRUD, validation, publish/activate, versions, runs, approvals, restricted HTTP connections, credential rotation, and inbound-hook rotation.
* `assets.materializeTransform`, `derivatives`, `generate`, and `automation` cover durable v2 transforms, generated images, and governed MCP discovery.
* `ChunkedUploadController` is the framework-neutral upload engine shared by the SDK and widget; it owns per-part SHA-256, bounded concurrency, retries, cancellation, persistence, fingerprint validation, and server-part reconciliation.

## CLI command patterns

The command group is `stackshift asset`; `stackshift assets` is an alias. Body-taking operations accept `--data` or `--file`. Add `--output json` for automation, `--wait` to stream supported migration/relocation/OCR progress, and `--poll-interval` to change the two-second default. Risky cancellation/deletion commands prompt unless `--yes` is supplied.

* Connection commands: `connection-create`, `connections`, `connection-get`, `connection-update`, `connection-verify`, and `connection-delete`.
* Storage commands: `s2-buckets`, `s2-bucket-create`, `bucket-storage-set`, and `relocate`.
* Migration commands: `migration-start`, `migrations`, `migration-get`, `migration-cancel`, `migration-item-retry`, and `migration-report`.
* OCR and widget-backend commands: `ocr-start`, `ocr-get`, `ocr-retry`, and `upload-capability-create`.
* Media commands: `transform-run`, `derivatives`, `generate`, and `automation`.
* Workflow commands: catalog/list/create/get/draft-update/validate/publish/activate, versions/runs, run detail/cancel/retry, approvals, connections, credential rotation, and inbound-hook rotation.

```bash theme={null}
stackshift asset connections --output json
stackshift asset connection-verify CONNECTION_UUID --output json
stackshift asset bucket-storage-set BUCKET_UUID --data '{"storage_mode":"managed","expected_revision":4}' --output json
stackshift asset relocate BUCKET_UUID --wait --data '{"dry_run":true}' --output json
stackshift asset migrations --query limit=50 --output json
stackshift asset migration-report MIGRATION_UUID --query format=csv --download ./migration.csv
stackshift asset ocr-start ASSET_UUID --wait --data '{"language":"eng"}' --output json
stackshift asset workflow-catalog --output json
stackshift asset workflow-run-get RUN_UUID --output json
```

## Durability and concurrency guarantees

* Production runs a dedicated Assets worker with four durable-job slots. External provider work and OCR are separately bounded to two concurrent operations each by default.
* Job and migration-item claims use database leases, heartbeats, unique lease tokens, fencing, expired-lease recovery, bounded attempts, and monotonic persisted progress. A stale worker cannot checkpoint or complete work after losing its lease.
* Worker crashes and restarts recover expired work. Duplicate job delivery and repeated inventory are idempotent; migration source identities and checksum checks prevent duplicate assets.
* Streaming uses bounded temporary scratch rather than loading entire provider objects into memory. Completion, cancellation, timeout, and recovery clean scratch and abort incomplete multipart uploads.
* Cancellation races fail closed: a canceled operation cannot later be completed by a stale claimant.

## Events, reports, and observable state

* Audit/event names include `asset.connection.created`, `.updated`, `.verified`, `.deleted`, `asset.bucket.storage_changed`, migration `.started`, `.completed`, `.failed`, `.canceled`, relocation `.completed`/`.failed`, and OCR `.completed`/`.failed`.
* Use `GET /assets/events` and existing Assets webhooks for customer-visible lifecycle evidence. Event payloads carry IDs and states, not stored secrets, signed URLs, or capability tokens.
* Migration reports remain available after completion, failure, or cancellation and are authoritative for item outcomes. `source_identity` is the provider-side correlation key.
* The dashboard Assets Operations area exposes Storage, Connections, Migrations, and OCR panels with verification results, live progress, report download, retry/cancel actions, relocation state, and geometry inspection.

## Recovery playbooks

* Stalled queue or worker crash: confirm worker/database/provider health, allow the lease to expire, restart normally, and verify persisted counters resume. Never edit leases or delete operation rows.
* Static credential rotation: update the encrypted connection secret, verify the connection, then revoke the old provider key. AWS AssumeRole rotation should retain the connection external ID while the customer role policy/trust is updated.
* Provider outage: keep connection and migration records. Restore provider access first; managed objects remain independent while objects recorded on the unavailable backend can produce origin failures.
* `checksum_mismatch`: leave the source reference unchanged, remove/quarantine the bad destination object, investigate transport/provider integrity, and retry.
* `source_delete_failed`: the verified destination is already authoritative. Restore source-provider access and remove only the recorded old object; do not roll back the database storage reference.
* OCR `provider_failed`: verify the asset is readable and Poppler, Tesseract, requested language data, and scratch capacity are healthy, then retry the extraction ID.
* Multipart cleanup alert: restore the exact provider connection, identify incomplete uploads by the known StackShift prefix/session identity, and abort only those uploads. Never bulk-delete a customer bucket.

## Security, deletion, and billing invariants

* Secrets are encrypted with connection-specific authenticated data, redacted from responses, and forbidden from logs, reports, events, and URLs. Browser capabilities are stored hashed and expire within one hour.
* Generic endpoints require public HTTPS, reject redirects and userinfo, validate DNS before use, and revalidate resolved addresses at connection time to block private/reserved targets and DNS rebinding.
* A connection or S2 bucket cannot be deleted while referenced by bucket storage, active uploads, migrations, relocations, or available storage objects. Remove references safely; do not bypass the check.
* Relocation never deletes the source before destination checksum verification and atomic reference commit. A failed relocation remains readable from the original backend.
* Managed, BYOB, and S2 assets all count toward logical Assets quota, ingress/egress, processing, OCR, and CDN usage. Only StackShift-managed Assets bytes accrue Assets managed physical-storage byte-hours; native S2 is accounted by the Object Store product.

## Expected result

<Check>
  Automation and operators use the same persisted state and can recover without editing storage references, exposing credentials, or deleting source data prematurely.
</Check>

## Common failures

<Warning>
  * A token has `assets:write` but the operation requires `assets:process` or `assets:admin`.
  * A client treats `202 Accepted` as completed rather than polling the migration or extraction resource.
  * A report download is parsed through the JSON envelope even though JSON/CSV report responses are raw downloadable bodies.
  * An operator retries broadly before restoring provider access, causing repeated bounded failures without changing the underlying condition.
</Warning>

## Related guides

<CardGroup cols={2}>
  <Card title="Storage connections, BYOB, and StackShift S2" href="/assets/storage-connections-and-byob">
    Configure AWS S3, Cloudflare R2, Wasabi, MinIO, generic S3, or native StackShift S2 without exposing customer storage credentials or changing delivery URLs.
  </Card>

  <Card title="Cloudinary, S3, R2, and S2 migrations" href="/assets/cloudinary-s3-and-s2-migrations">
    Inventory, dry-run, import, deduplicate, retry, cancel, and report durable migrations from Cloudinary or S3-compatible storage into StackShift Assets.
  </Card>

  <Card title="Embeddable Assets upload widget" href="/assets/embeddable-upload-widget">
    Install `@stackshift-cloud/assets-widget` for React or vanilla JavaScript with constrained backend-issued capabilities, resumable chunks, camera and URL input, cropping, previews, progress, retry, and cancellation.
  </Card>

  <Card title="OCR, document intelligence, and DAM search" href="/assets/ocr-and-document-search">
    Extract embedded PDF text or OCR PDF and image pages asynchronously, inspect normalized word geometry, cache by content identity, and search extracted text in the DAM.
  </Card>
</CardGroup>
