Files
Use the files API when you want to upload image bytes once, receive a file_id, and then reference that file from POST /v1/worlds.
Endpoints
| Endpoint | Scope | Purpose |
|---|---|---|
POST /v1/files | files:create | Upload an image and receive a file_id. |
GET /v1/files | files:read | List files uploaded by the current API key. |
Upload a file
Send a multipart/form-data request with a single file field:
API_KEY="spt_live_..."
curl -sX POST "https://api.spaitial.ai/v1/files" \
-H "Authorization: Bearer $API_KEY" \
-F "[email protected]"
Successful uploads return 201 Created:
{
"file_id": "file_abc123",
"content_type": "image/jpeg",
"file_size": 1843921,
"expires_at": "2026-05-21T10:42:00.000Z"
}
Allowed file types are JPEG, PNG, WebP, and GIF. The maximum file size is 25 MB. The API checks the detected MIME type from the file bytes, not just the uploaded filename or form content type.
Use the file in a world request
Pass the file_id as the world input:
FILE_ID=$(curl -sX POST "https://api.spaitial.ai/v1/files" \
-H "Authorization: Bearer $API_KEY" \
-F "[email protected]" | jq -r .file_id)
curl -sX POST "https://api.spaitial.ai/v1/worlds" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"input\": {
\"type\": \"file_id\",
\"file_id\": \"$FILE_ID\"
},
\"title\": \"Uploaded kitchen reference\"
}"
Using a file marks it as consumed. This is informational and visible in GET /v1/files; the object stays private until its lifecycle cleanup. Treat file_id values as one-generation inputs and upload again when you need a fresh reusable reference.
For an uploaded 360 panorama, use the same flow and add is_pano: true when creating the world:
PANO_FILE_ID=$(curl -sX POST "https://api.spaitial.ai/v1/files" \
-H "Authorization: Bearer $API_KEY" \
-F "[email protected]" | jq -r .file_id)
curl -sX POST "https://api.spaitial.ai/v1/worlds" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"input\": {
\"type\": \"file_id\",
\"file_id\": \"$PANO_FILE_ID\",
\"is_pano\": true
},
\"title\": \"Uploaded panorama\"
}"
Only set is_pano for equirectangular 360 panoramas. The API trusts the flag and skips suitability validation for that request.
List files
List files owned by the current API key user:
curl -s "https://api.spaitial.ai/v1/files?limit=20&offset=0" \
-H "Authorization: Bearer $API_KEY"
Response:
{
"files": [
{
"file_id": "file_abc123",
"content_type": "image/jpeg",
"file_size": 1843921,
"expires_at": "2026-05-21T10:42:00.000Z",
"created_at": "2026-05-20T10:42:00.000Z",
"consumed_at": null,
"status": "available"
}
],
"limit": 20,
"offset": 0,
"has_more": false
}
limit defaults to 20 and can be 1-100. offset defaults to 0.
File statuses
| Status | Meaning |
|---|---|
available | The file is still within its 24-hour TTL and has not been used yet. |
consumed | The file has been referenced by a world-generation request. |
expired | The file is past expires_at and can no longer be used. |
Errors
| HTTP | error.code | When it happens |
|---|---|---|
400 | INVALID_INPUT | Missing file, unsupported image type, or malformed list query. |
401 | UNAUTHORIZED | Missing, invalid, revoked, or expired API key. |
403 | FORBIDDEN | API key lacks files:create or files:read. |
403 | MODERATION_REJECTED | Uploaded image failed content moderation. |
404 | FILE_NOT_FOUND | file_id does not exist or belongs to another caller. |
404 | FILE_EXPIRED | file_id is expired or already consumed when resolving it for generation. |
413 | INVALID_INPUT | Uploaded file exceeds 25 MB. |
429 | RATE_LIMIT_EXCEEDED | The key exceeded its current rate-limit bucket. |
See Moderation for content screening and Validation for generation-suitability checks.