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.
POST /v2/generations
Content-Type: application/json
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Model to use for this generation. |
parts | array | Yes | One or two input items: exactly one prompt and at most one start_frame, in either order. |
duration | integer | Yes | Video duration in seconds. Must be a positive integer. Example: 10. |
aspectRatio | string | Yes | Output aspect ratio in width:height format. Example: 16:9. |
resolution | string | Yes | Output resolution. Example: 1080p. |
seed | integer (int64) | No | Random seed. Defaults to 0. |
Prompt
| Parameter | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Must be prompt. |
text | string | Yes | Video description. Must not be empty or contain only whitespace. |
Starting image
When including start_frame, provide an image reference in this format:
| Parameter | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Must be start_frame. |
image | object | Yes | Image reference. Provide exactly one of url or assetId. |
image.url | string | One of the two | Publicly accessible HTTPS image URL. |
image.assetId | string | One of the two | Existing, undeleted image asset in the current organization. A positive int64 represented as a decimal string, with no leading zeros. |
To use an uploaded image:
{ "type": "start_frame", "image": { "assetId": "123456789" } }
Images supplied by URL must meet these requirements:
| Property | Requirement |
|---|---|
| Access | Public HTTPS, without login, cookies, or additional request headers. Signed query parameters are allowed. |
| URL | No username, password, or # fragment. Must not point to localhost or a private network. Redirect targets must meet the same requirements. |
| Format | JPEG, PNG, or WebP, validated from the file content. |
| Size | At most 10 MiB (10,485,760 bytes). |
| Dimensions | Width 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.
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}.
{ "id": "123456789" }
| Field | Type | Description |
|---|---|---|
id | string | Generation 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.
GET /v2/generations/{id}
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | ID 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.
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.
{
"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.
| Field | Type | Description |
|---|---|---|
id | string | Generation ID. |
status | string | Generation status, listed below. |
output | object | null | Result information or null when succeeded; null for all other statuses. |
output.videoUrl | string | null | Video download URL. |
output.urlExpiresAt | string | null | Download URL expiration time. |
error | object | null | Failure information when failed; otherwise null. |
error.code | string | Failure code. See Generation Failures. |
error.message | string | Failure description. |
createdAt | string | Generation creation time. |
Statuses
| Status | Meaning | Action |
|---|---|---|
queued | Waiting to run. | Continue polling. |
processing | Preparing, generating, or undergoing moderation. | Continue polling. |
succeeded | Generation completed. | Check the download URL and retrieve the video. |
failed | Generation or moderation failed. | Stop polling and check error. |
canceled | Generation 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.
POST /v1/assets
Content-Type: multipart/form-data
Form parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
file | binary | Yes | One 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 type | Extensions | Dimensions and duration |
|---|---|---|
| Image | jpg, jpeg, png, webp | Width and height each 16–10,000 pixels; width-to-height ratio 0.01–100. |
| Video | mp4, ts | Width 16–7,680 pixels; height 16–4,320 pixels; width-to-height ratio 0.1–10; duration 0.1–3,600 seconds. |
| Audio | wav, mp3, aac, flac | Duration 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.
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.
{ "id": 123456789 }
| Field | Type | Description |
|---|---|---|
id | integer (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:
{ "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.
GET /v1/assets/{id}
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | integer (int64) | Yes | Asset ID returned by the upload endpoint. |
Example request
Replace 123456789 with the asset ID.
curl https://api.sand.ai/v1/assets/123456789 \
-H "Authorization: Bearer $SAND_API_KEY"
Response
A successful request returns HTTP 200 OK.
{
"id": 123456789,
"url": "https://files.example.com/start-frame.png?signature=example"
}
| Field | Type | Description |
|---|---|---|
id | integer (int64) | Asset ID. |
url | string | File 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.
DELETE /v1/assets/{id}
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | integer (int64) | Yes | ID of the asset to delete. |
No request body is required.
Example request
Replace 123456789 with the asset ID.
curl -X DELETE https://api.sand.ai/v1/assets/123456789 \
-H "Authorization: Bearer $SAND_API_KEY"
Response
A successful deletion returns HTTP 200 OK.
{ "id": 123456789 }
| Field | Type | Description |
|---|---|---|
id | integer (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.