Skip to main content

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

EndpointScopePurpose
POST /v1/filesfiles:createUpload an image and receive a file_id.
GET /v1/filesfiles:readList 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" \

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

StatusMeaning
availableThe file is still within its 24-hour TTL and has not been used yet.
consumedThe file has been referenced by a world-generation request.
expiredThe file is past expires_at and can no longer be used.

Errors

HTTPerror.codeWhen it happens
400INVALID_INPUTMissing file, unsupported image type, or malformed list query.
401UNAUTHORIZEDMissing, invalid, revoked, or expired API key.
403FORBIDDENAPI key lacks files:create or files:read.
403MODERATION_REJECTEDUploaded image failed content moderation.
404FILE_NOT_FOUNDfile_id does not exist or belongs to another caller.
404FILE_EXPIREDfile_id is expired or already consumed when resolving it for generation.
413INVALID_INPUTUploaded file exceeds 25 MB.
429RATE_LIMIT_EXCEEDEDThe key exceeded its current rate-limit bucket.

See Moderation for content screening and Validation for generation-suitability checks.