Uploads

Create up to 100 upload sessions in one batch, send bytes directly to object storage, then complete each session and follow finalization and scanning in real time.

1. Create batch2. PUT bytes3. Complete4. Track status
POST/api/upload-batches
201 Created

Create presigned upload sessions for one or more files.

Required scopeassets:write
Request body
{
  "bucketId": "bucket_uuid",
  "files": [{
    "filename": "campaign-hero.webp",
    "path": "launch/",
    "contentType": "image/webp",
    "size": 2841024
  }]
}
Response
{
  "id": "batch_uuid",
  "status": "active",
  "totalFiles": 1,
  "files": [{
    "id": "session_uuid",
    "status": "created",
    "uploadUrl": "https://storage.example/presigned-put",
    "expiresAt": "2026-08-17T19:01:00"
  }]
}
PUT{uploadUrl}
200 OK

Upload the raw file bytes to the presigned URL. This request goes to object storage, not the SteadyLink API.

Upload bytes
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @campaign-hero.webp
POST/api/upload-sessions/{session_id}/complete
202 Accepted

Queue finalization, malware scanning, metadata extraction, and revision creation.

Required scopeassets:write
Complete safely
curl -X POST \
  "https://api.steadylink.io/api/upload-sessions/$SESSION_ID/complete" \
  -H "X-API-Key: $STEADYLINK_API_KEY" \
  -H "Idempotency-Key: upload-$SESSION_ID"
The idempotency key applies to upload completion only. Reusing a different key for the same session returns 409. A terminal session returns its existing terminal payload.
GET/api/upload-batches/{batch_id}
200 OK

Read aggregate and per-file upload status.

Required scopeassets:read

Terminal states

NameTypeDescription
readysuccess

The file is finalized and available under its configured delivery policy.

blockedterminal

The malware scanner or bucket policy rejected the file.

failedterminal

Finalization could not complete. Inspect the error object.

cancelledterminal

The session was cancelled before completion.

GET/api/events/stream
200 OK

Open a server-sent event stream for upload and scan state changes in the workspace.

Required scopeassets:read
Event
event: upload.updated
data: {"type":"upload.updated","upload":{"id":"session_uuid","status":"scanning"}}
Heartbeats arrive about every 15 seconds. Reconnect with normal SSE retry behavior if the connection closes.
DELETE/api/upload-sessions/{session_id}
200 OK

Cancel an upload that has not reached a terminal state.

Required scopeassets:write