Browse the API docs
Endpoint reference

Assets and Uploads

The Crayo Assets API manages the media library that every other endpoint reads from. Import a file from a public https URL with one call, or upload bytes directly through a signed URL in three steps, and get back an asset id.

List assets

GET/v1/assets

Lists the media in your library, newest first. Every file you upload, import, or generate lands here, and an asset id is what every other endpoint takes as input.

Credits:
Free
Rate limit:
Default tier, 2/s and 50/min

Parameters

NameInTypeRequiredDescription
typequerystringNoFilter by media type.imageaudiovideo
categoryquerystringNoFilter by how the asset was made, for example asset for uploads, generation for images, or voiceover for narration.
limitqueryintegerNoAssets per page. 1 to 100.default 50
offsetqueryintegerNoNumber of assets to skip.default 0

Request

curl
curl "https://api.crayo.ai/v1/assets?type=video" \
  -H "Authorization: Bearer $CRAYO_API_KEY"

Response

200 application/json
{
  "success": true,
  "total": 128,
  "hasMore": true,
  "assets": [
    {
      "id": "cm7x1k2p40001abcd",
      "name": "hook-clip.mp4",
      "key": "user-uploads/cm7x0v8qa0000abcd/api/9f1.../hook-clip.mp4",
      "url": "https://cdn-crayo.com/user-uploads/cm7x0v8qa0000abcd/api/9f1.../hook-clip.mp4",
      "type": "video",
      "category": "asset",
      "length": 12.4,
      "size": 8421376,
      "width": 1080,
      "height": 1920,
      "thumbnail": "user-uploads/cm7x0v8qa0000abcd/api/9f1.../thumb.jpg",
      "thumbnailUrl": "https://cdn-crayo.com/user-uploads/cm7x0v8qa0000abcd/api/9f1.../thumb.jpg",
      "createdAt": "2026-08-21T14:02:11.000Z"
    }
  ]
}

Errors

  • 401MISSING_API_KEYNo Authorization header was sent, or it does not carry a crayo_sk_ key.
  • 401UNAUTHORIZEDThe key sent is malformed, expired, or revoked.
  • 429RATE_LIMITEDOver the rate limit. Wait Retry-After seconds.
  • 500SERVER_ERRORSomething failed on our side. Retry with backoff.

Get asset

GET/v1/assets/{id}

Returns one asset you own, including its playable url and its duration in seconds. Read length here before building scenes: the project schema is measured in milliseconds and per-second endpoints reject assets with no known duration.

Credits:
Free
Rate limit:
Default tier, 2/s and 50/min

Parameters

NameInTypeRequiredDescription
idpathstringYesThe asset id.

Request

curl
curl "https://api.crayo.ai/v1/assets/cm7x1k2p40001abcd" \
  -H "Authorization: Bearer $CRAYO_API_KEY"

Response

200 application/json
{
  "success": true,
  "asset": {
    "id": "cm7x1k2p40001abcd",
    "name": "hook-clip.mp4",
    "key": "user-uploads/cm7x0v8qa0000abcd/api/9f1.../hook-clip.mp4",
    "url": "https://cdn-crayo.com/user-uploads/cm7x0v8qa0000abcd/api/9f1.../hook-clip.mp4",
    "type": "video",
    "category": "asset",
    "length": 12.4,
    "size": 8421376,
    "width": 1080,
    "height": 1920,
    "thumbnail": "user-uploads/cm7x0v8qa0000abcd/api/9f1.../thumb.jpg",
    "thumbnailUrl": "https://cdn-crayo.com/user-uploads/cm7x0v8qa0000abcd/api/9f1.../thumb.jpg",
    "createdAt": "2026-08-21T14:02:11.000Z"
  }
}

Errors

  • 401MISSING_API_KEYNo Authorization header was sent, or it does not carry a crayo_sk_ key.
  • 401UNAUTHORIZEDThe key sent is malformed, expired, or revoked.
  • 404NOT_FOUNDNo asset with that id belongs to your account.
  • 429RATE_LIMITEDOver the rate limit. Wait Retry-After seconds.
  • 500SERVER_ERRORSomething failed on our side. Retry with backoff.

Rename asset

PATCH/v1/assets/{id}

Changes the display name of an asset you own. Only the name changes: the file, its url, and every project that references it stay exactly as they are.

Credits:
Free
Rate limit:
Default tier, 2/s and 50/min

Parameters

NameInTypeRequiredDescription
idpathstringYesThe asset id.
namebodystringYesThe new display name. Non-empty, max 200 characters. Leading and trailing whitespace is trimmed.

Request

curl
curl -X PATCH "https://api.crayo.ai/v1/assets/cm7x1k2p40001abcd" \
  -H "Authorization: Bearer $CRAYO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Hook clip v2"
}'

Response

200 application/json
{
  "success": true,
  "asset": {
    "id": "cm7x1k2p40001abcd",
    "name": "Hook clip v2",
    "key": "user-uploads/cm7x0v8qa0000abcd/api/9f1.../hook-clip.mp4",
    "url": "https://cdn-crayo.com/user-uploads/cm7x0v8qa0000abcd/api/9f1.../hook-clip.mp4",
    "type": "video",
    "category": "asset",
    "length": 12.4,
    "size": 8421376,
    "width": 1080,
    "height": 1920,
    "thumbnail": "user-uploads/cm7x0v8qa0000abcd/api/9f1.../thumb.jpg",
    "thumbnailUrl": "https://cdn-crayo.com/user-uploads/cm7x0v8qa0000abcd/api/9f1.../thumb.jpg",
    "createdAt": "2026-08-21T14:02:11.000Z"
  }
}

Errors

  • 400VALIDATION_ERRORname is missing, empty, or too long.
  • 400UNKNOWN_FIELDThe body carries a field other than name.
  • 401MISSING_API_KEYNo Authorization header was sent, or it does not carry a crayo_sk_ key.
  • 401UNAUTHORIZEDThe key sent is malformed, expired, or revoked.
  • 404NOT_FOUNDNo asset with that id belongs to your account.
  • 429RATE_LIMITEDOver the rate limit. Wait Retry-After seconds.
  • 500SERVER_ERRORSomething failed on our side. Retry with backoff.

Import asset from URL

POST/v1/assets

Downloads a file from a public https URL and stores it as an asset. This is the fastest way to bring in media you already host. Files above the import ceiling have to go through the upload flow instead.

Credits:
Free
Rate limit:
Uploads tier, 2/s and 20/min

Parameters

NameInTypeRequiredDescription
urlbodystringYesPublic https URL of the image, audio, or video file to import. Must be reachable and at most 100MB.
namebodystringNoDisplay name for the asset. Defaults to the filename in the URL. Max 200 characters.

Request

curl
curl -X POST "https://api.crayo.ai/v1/assets" \
  -H "Authorization: Bearer $CRAYO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://example.com/media/hook-clip.mp4",
  "name": "Hook clip"
}'

Response

200 application/json
{
  "success": true,
  "asset": {
    "id": "cm7x1k2p40001abcd",
    "name": "hook-clip.mp4",
    "key": "user-uploads/cm7x0v8qa0000abcd/api/9f1.../hook-clip.mp4",
    "url": "https://cdn-crayo.com/user-uploads/cm7x0v8qa0000abcd/api/9f1.../hook-clip.mp4",
    "type": "video",
    "category": "asset",
    "length": 12.4,
    "size": 8421376,
    "width": 1080,
    "height": 1920,
    "thumbnail": "user-uploads/cm7x0v8qa0000abcd/api/9f1.../thumb.jpg",
    "thumbnailUrl": "https://cdn-crayo.com/user-uploads/cm7x0v8qa0000abcd/api/9f1.../thumb.jpg",
    "createdAt": "2026-08-21T14:02:11.000Z"
  }
}

Errors

  • 400VALIDATION_ERRORThe URL could not be fetched, or it is not a public https address.
  • 401MISSING_API_KEYNo Authorization header was sent, or it does not carry a crayo_sk_ key.
  • 401UNAUTHORIZEDThe key sent is malformed, expired, or revoked.
  • 402STORAGE_LIMIT_EXCEEDEDThe file would exceed your storage quota.
  • 413FILE_TOO_LARGEThe file is larger than 100MB. Use the upload flow.
  • 415UNSUPPORTED_MEDIA_TYPEThe URL does not serve a supported image, audio, or video type.
  • 429RATE_LIMITEDOver the rate limit. Wait Retry-After seconds.
  • 500SERVER_ERRORSomething failed on our side. Retry with backoff.

Delete asset

DELETE/v1/assets/{id}

Permanently deletes an asset and frees its storage. Projects that already reference the file keep their timeline entry, but the media behind it stops resolving, so delete only what nothing depends on.

Credits:
Free
Rate limit:
Default tier, 2/s and 50/min

Parameters

NameInTypeRequiredDescription
idpathstringYesThe asset id.

Request

curl
curl -X DELETE "https://api.crayo.ai/v1/assets/cm7x1k2p40001abcd" \
  -H "Authorization: Bearer $CRAYO_API_KEY"

Response

200 application/json
{
  "success": true
}

Errors

  • 401MISSING_API_KEYNo Authorization header was sent, or it does not carry a crayo_sk_ key.
  • 401UNAUTHORIZEDThe key sent is malformed, expired, or revoked.
  • 404NOT_FOUNDNo asset with that id belongs to your account.
  • 409ASSET_IN_USEThe asset is the source of an AutoClip job that is still running.
  • 429RATE_LIMITEDOver the rate limit. Wait Retry-After seconds.
  • 500SERVER_ERRORSomething failed on our side. Retry with backoff.

Create upload

POST/v1/uploads

Step one of the upload flow. Declare the file you are about to send and get back a signed URL to PUT the bytes to. The URL is single-use and short-lived, so start the transfer right away.

  • PUT the raw bytes to the returned url with exactly the content-type header it hands back, and begin within 5 minutes.
  • Nothing is stored until you complete the upload. A file that is never completed is discarded.
Credits:
Free
Rate limit:
Uploads tier, 2/s and 20/min

Parameters

NameInTypeRequiredDescription
filenamebodystringYesName of the file, used as the asset name. Max 100 characters after sanitizing.
content_typebodystringYesMIME type of the file. It must match the bytes you send. One of the supported image, audio, or video types.
size_bytesbodyintegerYesSize of the file in bytes. Images 20MB, audio 100MB, video 1GB.

Request

curl
curl -X POST "https://api.crayo.ai/v1/uploads" \
  -H "Authorization: Bearer $CRAYO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "filename": "hook-clip.mp4",
  "content_type": "video/mp4",
  "size_bytes": 8421376
}'

Response

200 application/json
{
  "success": true,
  "upload": {
    "id": "5f0c9a1e-7c1b-4a5e-9f0e-6b2a3c4d5e6f",
    "url": "https://uploads.crayo.ai/user-uploads/.../staging/hook-clip.mp4?X-Amz-Signature=...",
    "method": "PUT",
    "headers": {
      "content-type": "video/mp4"
    },
    "expires_at": "2026-08-21T14:07:11.000Z"
  }
}

Errors

  • 400VALIDATION_ERRORA field is missing or size_bytes is not a whole number.
  • 401MISSING_API_KEYNo Authorization header was sent, or it does not carry a crayo_sk_ key.
  • 401UNAUTHORIZEDThe key sent is malformed, expired, or revoked.
  • 402STORAGE_LIMIT_EXCEEDEDThe file would exceed your storage quota.
  • 413FILE_TOO_LARGEsize_bytes is above the cap for that media type.
  • 415UNSUPPORTED_MEDIA_TYPEcontent_type is not a supported type.
  • 429RATE_LIMITEDOver the rate limit. Wait Retry-After seconds.
  • 500SERVER_ERRORSomething failed on our side. Retry with backoff.

Complete upload

POST/v1/uploads/{id}/complete

Step three of the upload flow. Call it once the PUT finishes to have the file checked, measured, and turned into an asset. Size, MIME type, and your storage quota are all enforced here, so a file only becomes an asset if it passes.

Credits:
Free
Rate limit:
Uploads tier, 2/s and 20/min

Parameters

NameInTypeRequiredDescription
idpathstringYesThe upload id returned by POST /v1/uploads.

Request

curl
curl -X POST "https://api.crayo.ai/v1/uploads/5f0c9a1e-7c1b-4a5e-9f0e-6b2a3c4d5e6f/complete" \
  -H "Authorization: Bearer $CRAYO_API_KEY"

Response

200 application/json
{
  "success": true,
  "asset": {
    "id": "cm7x1k2p40001abcd",
    "name": "hook-clip.mp4",
    "key": "user-uploads/cm7x0v8qa0000abcd/api/9f1.../hook-clip.mp4",
    "url": "https://cdn-crayo.com/user-uploads/cm7x0v8qa0000abcd/api/9f1.../hook-clip.mp4",
    "type": "video",
    "category": "asset",
    "length": 12.4,
    "size": 8421376,
    "width": 1080,
    "height": 1920,
    "thumbnail": "user-uploads/cm7x0v8qa0000abcd/api/9f1.../thumb.jpg",
    "thumbnailUrl": "https://cdn-crayo.com/user-uploads/cm7x0v8qa0000abcd/api/9f1.../thumb.jpg",
    "createdAt": "2026-08-21T14:02:11.000Z"
  }
}

Errors

  • 400UPLOAD_NOT_FOUNDNo bytes have reached the signed URL yet.
  • 401MISSING_API_KEYNo Authorization header was sent, or it does not carry a crayo_sk_ key.
  • 401UNAUTHORIZEDThe key sent is malformed, expired, or revoked.
  • 402STORAGE_LIMIT_EXCEEDEDThe finished file would exceed your storage quota.
  • 404NOT_FOUNDThe upload id is unknown or older than 2 hours.
  • 413FILE_TOO_LARGEThe stored file is larger than the cap or than size_bytes.
  • 415UNSUPPORTED_MEDIA_TYPEThe stored bytes do not match the content_type you declared.
  • 429RATE_LIMITEDOver the rate limit. Wait Retry-After seconds.
  • 500SERVER_ERRORSomething failed on our side. Retry with backoff.
New to the Crayo API? See what it is forUse cases, pricing and the console walkthrough live on the API feature page.

FAQs

Frequent questions

POST /v1/assets downloads a public https file up to 100MB in one call. Larger files go through the upload flow, which accepts video up to 1GB, audio up to 100MB and images up to 20MB.

No. Getting media in spends storage, not credits. A file that would push you over your storage quota is rejected with 402 STORAGE_LIMIT_EXCEEDED, and DELETE /v1/assets/{id} frees space.

Declare the file with POST /v1/uploads, PUT the raw bytes to the signed URL it returns within 5 minutes using the content-type header it hands back, then call POST /v1/uploads/{id}/complete to turn the file into an asset.

Images: image/jpeg, image/png, image/webp, image/gif. Audio: audio/mpeg, audio/mp4, audio/wav, audio/x-wav, audio/aac, audio/ogg, audio/webm, audio/flac. Video: video/mp4, video/quicktime, video/webm, video/x-matroska.

Still have questions?

Contact our 24/7 support team for any concerns or inquiries.

Get in touch