Skip to content
On this page

API reference

Parameters, examples, and responses for generations and assets.

Create a Generation

Create an asynchronous video generation. Use Bearer authentication, then retrieve the generation to check its status and result.

http
POST /v2/generations
Content-Type: application/json

Request body

ParameterTypeRequiredDescription
modelstringYesModel to use for this generation.
partsarrayYesOne or two input items: exactly one prompt and at most one start_frame, in either order.
durationintegerYesVideo duration in seconds. Must be a positive integer. Example: 10.
aspectRatiostringYesOutput aspect ratio in width:height format. Example: 16:9.
resolutionstringYesOutput resolution. Example: 1080p.
seedinteger (int64)NoRandom seed. Defaults to 0.

Prompt

ParameterTypeRequiredDescription
typestringYesMust be prompt.
textstringYesVideo description. Must not be empty or contain only whitespace.

Starting image

When including start_frame, provide an image reference in this format:

ParameterTypeRequiredDescription
typestringYesMust be start_frame.
imageobjectYesImage reference. Provide exactly one of url or assetId.
image.urlstringOne of the twoPublicly accessible HTTPS image URL.
image.assetIdstringOne of the twoExisting, undeleted image asset in the current organization. A positive int64 represented as a decimal string, with no leading zeros.

To use an uploaded image:

json
{ "type": "start_frame", "image": { "assetId": "123456789" } }

Images supplied by URL must meet these requirements:

PropertyRequirement
AccessPublic HTTPS, without login, cookies, or additional request headers. Signed query parameters are allowed.
URLNo username, password, or # fragment. Must not point to localhost or a private network. Redirect targets must meet the same requirements.
FormatJPEG, PNG, or WebP, validated from the file content.
SizeAt most 10 MiB (10,485,760 bytes).
DimensionsWidth and height each 16–10,000 pixels; at most 16,000,000 pixels in total.

Keep the URL accessible until the creation request completes. Starting frames must be images. Prompts and images are subject to content moderation.

Only the fields listed above are accepted. Unknown fields, duplicate JSON properties, explicit null values, and duplicate input types are rejected. Field names and type values are case-sensitive. duration and seed must be JSON integers, not strings or decimal numbers.

Example request

This example uses magi-2-preview-latest. Replace model with the model you want to use and image.url with your image URL.

bash
curl https://api.sand.ai/v2/generations \
  -H "Authorization: Bearer $SAND_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "model": "magi-2-preview-latest",
    "parts": [
      {"type": "prompt", "text": "The camera slowly moves forward as a corgi runs toward it through the snow."},
      {"type": "start_frame", "image": {"url": "https://images.example.com/frame.png"}}
    ],
    "duration": 10,
    "aspectRatio": "16:9",
    "resolution": "1080p",
    "seed": 12345
  }'

Response

A successful request returns HTTP 202 Accepted. The video is generated asynchronously. The Location response header is /v2/generations/{id}.

json
{ "id": "123456789" }
FieldTypeDescription
idstringGeneration ID. Save it to retrieve the status and result.

Creation requests are not guaranteed to be idempotent. Repeated requests may create multiple generations. See Retries, Rate Limits, and Errors.

Retrieve a Generation

Retrieve the status and result of a generation in the current organization. Requires Bearer authentication.

http
GET /v2/generations/{id}

Path parameters

ParameterTypeRequiredDescription
idstringYesID returned when creating the generation. A positive int64 represented as a decimal string, with no leading zeros.

Example request

Set SAND_GENERATION_ID to the saved generation ID. Use the same ID if polling is interrupted.

bash
export SAND_GENERATION_ID='123456789'
curl "https://api.sand.ai/v2/generations/$SAND_GENERATION_ID" \
  -H "Authorization: Bearer $SAND_API_KEY"

Response

A successful retrieval returns HTTP 200 OK and Cache-Control: no-store. Check status for the generation outcome.

json
{
  "id": "123456789",
  "status": "succeeded",
  "output": {
    "videoUrl": "https://files.example.com/video.mp4?signature=example",
    "urlExpiresAt": "2026-11-02T03:00:00.000Z"
  },
  "error": null,
  "createdAt": "2026-11-02T01:55:00.000Z"
}

All five top-level fields are always present. Timestamps use RFC 3339 in UTC with millisecond precision.

FieldTypeDescription
idstringGeneration ID.
statusstringGeneration status, listed below.
outputobject | nullResult information or null when succeeded; null for all other statuses.
output.videoUrlstring | nullVideo download URL.
output.urlExpiresAtstring | nullDownload URL expiration time.
errorobject | nullFailure information when failed; otherwise null.
error.codestringFailure code. See Generation Failures.
error.messagestringFailure description.
createdAtstringGeneration creation time.

Statuses

StatusMeaningAction
queuedWaiting to run.Continue polling.
processingPreparing, generating, or undergoing moderation.Continue polling.
succeededGeneration completed.Check the download URL and retrieve the video.
failedGeneration or moderation failed.Stop polling and check error.
canceledGeneration was canceled.Stop polling.

Poll about every 5 seconds, keeping the combined request rate within your organization's rate limits.

Download the video

Check that output and output.videoUrl are not null before downloading. The download does not require an API key. URLs are valid for 60 minutes; use urlExpiresAt for the exact expiration. Retrieve the generation again to obtain a fresh URL.

If the result is unavailable, output or its URL fields may be null. Later moderation decisions can affect access; use the latest retrieval response.

If the generation is missing, deleted, or belongs to another organization, the endpoint returns 404 generation_not_found. See Errors for other request failures.

Upload an Asset

Upload an image, video, or audio file and receive an asset ID. Requires Bearer authentication.

http
POST /v1/assets
Content-Type: multipart/form-data

Form parameters

ParameterTypeRequiredDescription
filebinaryYesOne file with a supported filename extension.

Both the file and the complete multipart request must be at most 10 MiB (10,485,760 bytes). Allow space for multipart boundaries and form metadata. Extensions are case-insensitive, and the file content must be decodable.

Media typeExtensionsDimensions and duration
Imagejpg, jpeg, png, webpWidth and height each 16–10,000 pixels; width-to-height ratio 0.01–100.
Videomp4, tsWidth 16–7,680 pixels; height 16–4,320 pixels; width-to-height ratio 0.1–10; duration 0.1–3,600 seconds.
Audiowav, mp3, aac, flacDuration 0.1–3,600 seconds.

Video and audio files must contain valid media streams and timing information. Images and videos are subject to content moderation.

Example request

Replace ./start-frame.png with a local file path.

bash
curl https://api.sand.ai/v1/assets \
  -H "Authorization: Bearer $SAND_API_KEY" \
  -F "file=@./start-frame.png"

When using cURL -F or a client's file upload feature, let the client set Content-Type and the multipart boundary.

Response

A successful upload returns HTTP 200 OK.

json
{ "id": 123456789 }
FieldTypeDescription
idinteger (int64)Asset ID. Save it to retrieve, delete, or reference the asset.

Use Retrieve an Asset to obtain a file URL. When referencing an image in Create a Generation, pass assetId as a decimal string:

json
{ "type": "start_frame", "image": { "assetId": "123456789" } }

Asset IDs may exceed JavaScript's safe integer range. Use a JSON parser that preserves large integers before converting the ID to a string.

See Asset Errors for failure responses.

Retrieve an Asset

Get a file URL for an asset in the current organization. Requires Bearer authentication.

http
GET /v1/assets/{id}

Path parameters

ParameterTypeRequiredDescription
idinteger (int64)YesAsset ID returned by the upload endpoint.

Example request

Replace 123456789 with the asset ID.

bash
curl https://api.sand.ai/v1/assets/123456789 \
  -H "Authorization: Bearer $SAND_API_KEY"

Response

A successful request returns HTTP 200 OK.

json
{
  "id": 123456789,
  "url": "https://files.example.com/start-frame.png?signature=example"
}
FieldTypeDescription
idinteger (int64)Asset ID.
urlstringFile URL, or an empty string "" if no URL is currently available.

Signed URLs are valid for 60 minutes. Retrieve the asset again after expiration to obtain a fresh URL. Check that url is not empty before downloading. The download does not require an API key.

A missing or deleted asset returns 404; an asset belonging to another organization returns 403. See Asset Errors for error codes.

Delete an Asset

Delete an asset in the current organization. Requires Bearer authentication.

http
DELETE /v1/assets/{id}

Path parameters

ParameterTypeRequiredDescription
idinteger (int64)YesID of the asset to delete.

No request body is required.

Example request

Replace 123456789 with the asset ID.

bash
curl -X DELETE https://api.sand.ai/v1/assets/123456789 \
  -H "Authorization: Bearer $SAND_API_KEY"

Response

A successful deletion returns HTTP 200 OK.

json
{ "id": 123456789 }
FieldTypeDescription
idinteger (int64)ID of the deleted asset.

A deleted asset cannot be retrieved or used in new generation requests. Retrieving or deleting it again returns 404. Deleting an asset does not cancel generations, and previously issued URLs may remain valid. Wait for related generations to finish before deleting input assets.

Accessing another organization's asset returns 403. See Asset Errors for error codes.