Quickstart
Upload an image, create a video generation, and retrieve the result.
Generate videos and manage image, video, and audio assets.
| Setting | Value |
|---|---|
| Base URL | https://api.sand.ai |
| Authentication | Bearer API key |
Authentication
Create a key on the API Keys page and include it in the request header:
Authorization: Bearer YOUR_API_KEY
Each API key belongs to an organization. Generations, assets, and usage are managed at the organization level. Keep keys on your server; do not expose them in browsers or mobile apps.
Before running the examples, set your API key:
export SAND_API_KEY='YOUR_API_KEY'
Quickstart
This example uses magi-2-preview-latest. Upload a starting image, create a generation, and retrieve the result.
1. Upload an image
Replace ./start-frame.png with a local image path.
curl https://api.sand.ai/v1/assets \
-H "Authorization: Bearer $SAND_API_KEY" \
-F "file=@./start-frame.png"
The response contains an asset ID:
{ "id": 123456789 }
2. Create a generation
Set image.assetId to the returned asset ID, as a string.
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": "A person turns and smiles as the camera slowly pulls back."},
{"type": "start_frame", "image": {"assetId": "123456789"}}
],
"duration": 10,
"aspectRatio": "16:9",
"resolution": "1080p"
}'
A successful request returns HTTP 202 Accepted and a generation ID:
{ "id": "987654321" }
Save the generation ID. The request has been accepted, and the video will be generated asynchronously. See Create a Generation for the full request format.
3. Retrieve the result
Set the generation ID and check its status:
export SAND_GENERATION_ID='987654321'
curl "https://api.sand.ai/v2/generations/$SAND_GENERATION_ID" \
-H "Authorization: Bearer $SAND_API_KEY"
queuedorprocessing: continue polling, typically every 5 seconds. Keep the total polling rate across all generations within your organization's limit.succeeded: check thatoutput.videoUrlis not null, then download the video.failed: stop polling and readerror.canceled: stop polling.
See Retrieve a Generation for the response fields and download URL expiration.
Resume polling
If the connection drops or polling stops, repeat step 3 with the saved generation ID. You can also use details.generation_id when it is included in a failed creation response.
Do not create another generation to resume polling: doing so may incur duplicate charges. See Retries.