Docs API reference
Markdown Get an API key

API referenceMedia and accounts

Media and Image URLs

Signed upload and download links for reference media and generated results. To upload, request an upload URL, then PUT the file bytes to it. Media endpoints cover audio and video; image endpoints cover images. Every link lasts 48 hours, and Sogni keeps generated media for about two days. Unlimited subscribers can also keep saved uploads to reuse across projects.

Treat every link as opaque. Use uploadUrl and downloadUrl exactly as returned. Don't parse, rebuild, or allowlist the host, and don't strip the query string: the signature lives there, and storage refuses unsigned requests. The storage host behind these links can change without notice.

#Get a media upload URL

GET /v1/media/uploadUrl Auth required

Returns a signed PUT URL for uploading one audio or video file. The URL is valid for 48 hours. Unknown query parameters return 400. Uploading an input for a jobId already claimed by another account returns 403.

#Query parameters

NameTypeInDescription
typerequiredstringqueryAsset type. Artist-side: referenceAudio, referenceVideo. Worker-side: complete, preview.
jobIdrequiredstringqueryJob identifier the asset belongs to.
idstringqueryArtifact identifier. Required for worker uploads. For artist uploads, omit it, or use referenceVideo1–referenceVideo3 or referenceAudio1–referenceAudio3 to fill numbered reference slots; pass the same id when downloading.
contentTypestringqueryMIME type of the file. Send the same value as the upload's Content-Type header. Video: video/mp4, video/quicktime, video/webm. Audio: audio/mp4, audio/mpeg, audio/flac, audio/wav, audio/x-wav, audio/wave. When omitted, referenceAudio is treated as audio/mp4 and referenceVideo as video/mp4.

#Response

{
  "status": "success",
  "data": {
    "uploadUrl": "https://<signed-storage-url>"
  }
}
How to upload. PUT the raw file bytes to uploadUrl (not multipart/form-data) with a Content-Type header equal to the contentType you requested. Storage returns 200 on success.
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: video/mp4" \
  --data-binary @reference.mp4

#Get a media download URL

GET /v1/media/downloadUrl Auth required

Returns a signed download URL, valid for 48 hours, for a previously uploaded asset or a completed job artifact. Request a fresh one when it expires. Sogni keeps generated media for about two days, so copy results you want to keep to your own storage. A deleted project's downloads return 404.

#Query parameters

NameTypeInDescription
typerequiredstringqueryAsset type. Same values as upload.
jobIdrequiredstringqueryJob identifier.
idstringqueryArtifact id.
contentTypestringqueryOptional MIME hint. The server uses the stored upload content type when available.
artifactstringqueryOptional. lastFrame returns the exported final frame of a Seedance 2.5 video that requested one; otherwise 404.

#Response

{
  "status": "success",
  "data": { "downloadUrl": "https://<signed-storage-url>" }
}

#Get an image upload URL

GET /v1/image/uploadUrl Auth required

Returns a signed PUT URL for one image. Same flow as media: PUT the raw bytes to uploadUrl with a Content-Type header equal to the contentType you requested. The URL is valid for 48 hours.

#Query parameters

NameTypeInDescription
typerequiredstringqueryAsset type. Artist-side: startingImage, cnImage, contextImage1–contextImage16, referenceImage, referenceImageEnd, referenceMask. Worker-side: complete, preview.
jobIdrequiredstringqueryJob identifier.
imageIdstringqueryArtifact id. Required for worker uploads.
contentTypestringqueryMIME type of the image: image/png, image/jpeg, image/jpg, image/webp, or image/gif. Defaults to image/png. Send the same value as the upload's Content-Type header.

#Response

{
  "status": "success",
  "data": {
    "uploadUrl": "https://<signed-storage-url>"
  }
}
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: image/png" \
  --data-binary @startingImage.png

#Get an image download URL

GET /v1/image/downloadUrl Auth required

Returns a signed download URL, valid for 48 hours, for an image artifact. Query parameters match the image upload endpoint.

#Response

{
  "status": "success",
  "data": {
    "downloadUrl": "https://<signed-storage-url>"
  }
}
Form uploads (legacy). The /v2 upload endpoints return an HTML form POST policy instead of a PUT URL. They still work, but new integrations should use the /v1 PUT endpoints above. The /v2 download endpoints are the same as their /v1 counterparts.

#Get a media upload form (legacy)

GET /v2/media/uploadUrl Auth required

Takes the same query parameters as /v1/media/uploadUrl. Returns a form POST URL plus fields for one media object up to maxSizeBytes (100 MB). The form expires after one hour.

#Response

{
  "status": "success",
  "data": {
    "url": "https://<signed-storage-url>",
    "fields": {
      "Content-Type": "video/mp4",
      "bucket": "<bucket>",
      "key": "video/2026-05-18/<jobId>/reference.mp4",
      "X-Amz-Algorithm": "AWS4-HMAC-SHA256",
      "X-Amz-Credential": "…",
      "X-Amz-Date": "…",
      "Policy": "<base64-encoded-policy>",
      "X-Amz-Signature": "<hex-signature>"
    },
    "maxSizeBytes": 104857600,
    "allowedContentTypes": [ "…" ]
  }
}

allowedContentTypes depends on the asset type:

  • Video uploads such as referenceVideo: video/mp4, video/quicktime, video/webm
  • Audio uploads such as referenceAudio: audio/mp4, audio/mpeg, audio/flac, audio/wav, audio/x-wav, audio/wave
  • Preview frames: image/jpeg, image/jpg, image/png, image/webp
How to upload with a form. POST to the returned url as multipart/form-data, including every key and value from fields unchanged, then your file field last. Storage returns 204 on success.

#Get an image upload form (legacy)

GET /v2/image/uploadUrl Auth required

Takes the same query parameters as /v1/image/uploadUrl. Returns a form POST URL plus fields, as for media, with allowedContentTypes of image/png, image/jpeg, image/jpg, image/webp, and image/gif.

#Get a media download URL (v2 path)

GET /v2/media/downloadUrl Auth required

Same endpoint as /v1/media/downloadUrl: same parameters and response.

#Get an image download URL (v2 path)

GET /v2/image/downloadUrl Auth required

Same endpoint as /v1/image/downloadUrl: same parameters and response.

Saved uploads. Unlimited subscribers can save an image, video, or audio file once and reuse it across projects without uploading it again. Saved uploads are private to the account. The JavaScript and Python SDKs use them automatically when you pass files to projects.create(), and expose projects.assets for explicit control; durable workflows take media_references URLs instead. Prepare, finalize, and bind require an active Unlimited plan (403 otherwise); listing, capabilities, and removal do not. Files are kept while the plan is active, and for 30 days after the later of the paid period's end and the last save or reuse.

#List saved uploads

GET /v1/assets Auth required

Returns data.assets, newest first, and data.limits (fileBytes, idleDays). Each record has id, name, bytes, contentType, state (uploading or ready), createdAt, and expiresAt (Unix milliseconds).

#Check saved-upload availability

GET /v1/assets/capabilities Auth required

Returns { enabled, limits }. enabled is false without an active plan or when saved storage is unavailable.

#Prepare a saved upload

POST /v1/assets/prepare Auth required

#Body

NameTypeInDescription
sha256requiredstringbodyLowercase hex SHA-256 of the file.
bytesrequiredintegerbodyFile size, from 1 to limits.fileBytes.
contentTyperequiredstringbodyimage/png, image/jpeg, image/webp, video/mp4, video/quicktime, video/webm, audio/mp4, audio/mpeg, audio/flac, audio/wav, audio/x-wav, or audio/wave.
namestringbodyOptional label, up to 80 characters.

If the same file is already saved, returns its record with reused: true and nothing to upload. Otherwise returns the record with reused: false, an uploadUrl, and uploadHeaders. PUT the exact bytes to uploadUrl within five minutes, sending exactly those headers. An upload that is never finalized expires after one hour.

#Finalize a saved upload

POST /v1/assets/:id/finalize Auth required

Send a JSON body ({} is fine). Verifies size, type, and checksum, then returns the ready record. A mismatch returns 409, an expired upload 410, and a busy entry 423.

#Attach a saved upload to a project

POST /v1/assets/:id/bind Auth required

Copies a ready saved upload into a project input slot before you submit the project through the SDK. Body: { projectId, type, id? }. projectId is the UUID you will submit; type is an image input type from the image upload endpoint, referenceVideo, or referenceAudio, and must match the file's media type; id selects a numbered reference slot. Returns { assetId, projectId, type, contentType }. A project ID already claimed by another account returns 403.

#Remove a saved upload

DELETE /v1/assets/:id Auth required

Deletes the saved file; data is {}. Inputs already copied into existing projects are not affected. An unknown ID, or one owned by another account, returns 404.