The Crayo API is a JSON REST API at https://api.crayo.ai authenticated with a bearer key created on the Developers page of the Crayo app. Every request sends an Authorization: Bearer header with a key that starts with crayo_sk_, and errors come back as a success false envelope with a stable code.
Keys are created on the Developers page of the Crayo app. Every key starts with crayo_sk_ and acts as the whole account, so keep it on a server and read it from an environment variable rather than shipping it in a client app.
The base URL is https://api.crayo.ai. Every request carries the key in the Authorization header. There is nothing else to sign and no session to keep alive. POST and PATCH bodies are JSON with a Content-Type: application/json header, GET and DELETE take no body, and request bodies are capped at 512KB.
curl "https://api.crayo.ai/v1/account" \
-H "Authorization: Bearer $CRAYO_API_KEY"A good first call is GET /v1/account. It is free and returns your plan, credit balances, storage usage and the rate limits that apply to the key.
The API spends the same credits as the Crayo app, from the same balance. Reads are free. Anything that generates or renders media costs credits, and they are spent when a request is accepted rather than when it finishes well, so a failed render or an AutoClip job that finds fewer clips than requested leaves them spent. View Tracker is the exception: a lookup that fails on our side is refunded.
| Credit type | Spent on |
|---|---|
| Image | Image, icon, and face swap generation. |
| Voiceover | Narration, voice changes, speech cleanup, and transcripts. Charged per second. |
| Export | Project renders. Charged per second of finished video. |
| Video | AutoClip jobs. Charged per requested clip. |
| Tracker | View Tracker. 1 credit per request for fresh data: each live lookup and each scheduled refresh. Stored reads are free. |
Storage is a separate budget. Uploads and imports cost no credits but count against your plan storage, and so does everything you generate or render. Going over returns 402 STORAGE_LIMIT_EXCEEDED.
Limits are per API key. Most endpoints share the default budget, while the expensive and the pollable endpoints get their own tiers.
| Tier | Per second | Per minute | Applies to |
|---|---|---|---|
| Default | 2 | 50 | Every endpoint not listed in another tier |
| Heavy | 2 | 10 | POST/v1/transcriptsPOST/v1/projectsPOST/v1/projects/{id}/exportPOST/v1/autoclipPOST/v1/speech-enhancer |
| Polling | 2 | 120 | GET/v1/projectsGET/v1/projects/{id}GET/v1/exportsGET/v1/exports/{id}GET/v1/autoclipGET/v1/autoclip/{id}GET/v1/speech-enhancerGET/v1/speech-enhancer/{id} |
| Uploads | 2 | 20 | POST/v1/assetsPOST/v1/uploadsPOST/v1/uploads/{id}/complete |
Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset. Going over returns 429 with code RATE_LIMITED and a Retry-After header in seconds.
View Tracker has its own, higher limits that count per account rather than per key, so a busy tracker integration never eats the budget of your other calls.
| Tier | Per second | Per minute | Applies to |
|---|---|---|---|
| Raw lookups | 5 | 200 | Every raw lookup under /v1/view-tracker/raw |
| Tracker reads | 5 | 300 | GET /v1/view-tracker/trackers and everything under it, GET /v1/view-tracker/usage |
| Tracker writes | 2 | 60 | POST /v1/view-tracker/trackers, PATCH and DELETE /v1/view-tracker/trackers/{id}, POST /v1/view-tracker/trackers/{id}/refresh |
| Batch create | 1 | 10 | POST /v1/view-tracker/trackers/batch |
Failures come back in one shape, with a stable code you can branch on and a message written for a human reading a log. Branch on the code: messages get clearer over time, codes do not change.
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "title is required"
}
}These four can come back from any endpoint.
| Status | Code | When |
|---|---|---|
| 401 | MISSING_API_KEY | No Authorization header was sent, or it does not carry a crayo_sk_ key. |
| 401 | UNAUTHORIZED | The key sent is malformed, expired, or revoked. |
| 429 | RATE_LIMITED | Over the rate limit. Wait Retry-After seconds. |
| 500 | SERVER_ERROR | Something failed on our side. Retry with backoff. |
Endpoint-specific codes are listed on each endpoint. The most common across the API are below, with the number of endpoints that can return each one.
| Status | Code | Endpoints |
|---|---|---|
| 400 | VALIDATION_ERROR | 39 |
| 400 | UNKNOWN_FIELD | 31 |
| 400 | INVALID_ASSET_TYPE | 3 |
| 402 | STORAGE_LIMIT_EXCEEDED | 3 |
| 402 | INSUFFICIENT_CREDITS | 30 |
| 403 | TARGET_PRIVATE | 15 |
| 404 | NOT_FOUND | 46 |
| 404 | TARGET_NOT_FOUND | 15 |
| 413 | FILE_TOO_LARGE | 3 |
| 415 | UNSUPPORTED_MEDIA_TYPE | 3 |
| 429 | CONCURRENT_REQUEST | 4 |
| 429 | RATE_LIMITED | 29 |
| 502 | UPSTREAM_ERROR | 15 |
| 503 | UPSTREAM_BUSY | 15 |
Renders, AutoClip jobs, speech enhancements and tracker refreshes run in the background. Register an https endpoint with POST /v1/webhooks and we send one signed POST the moment the work is done. The signing secret starts with crayo_whsec_ and is returned exactly once.
| Event | Fires when |
|---|---|
| export.completed | A project render finished. The payload carries the finished video asset. |
| export.failed | A project render failed. Credits stay spent. |
| autoclip.completed | An AutoClip job finished and its clips are ready. |
| autoclip.failed | An AutoClip job failed. |
| speech_enhancer.completed | A speech enhancement finished. Fetch it for stems and export the mix you want. |
| speech_enhancer.failed | A speech enhancement failed. Credits stay spent. |
| tracker.refreshed | A managed tracker was refreshed. The payload carries the latest reading, the new snapshot, new posts and removed post ids. |
| tracker.refresh_failed | A managed tracker refresh failed because the target is private, missing or unavailable. |
| tracker.paused | A managed tracker paused itself: out of credits, failing, or dormant. |
| tracker.alert | Something you asked to be alerted about happened on a tracker: a post went viral, a follower or view milestone was crossed, a post was removed, a new post appeared, or followers dropped. Pick what counts with alert_kinds on the tracker. |
| credits.low | Your tracker credits dropped below 10% of your monthly allotment. Sent once per cycle. |
Each delivery carries a crayo-signature header shaped like t=1755785271,v1=<hex>: an HMAC-SHA256 over <t>.<raw body> using your webhook secret. Deliveries are attempted up to 5 times, backing off exponentially from 30 seconds, and an endpoint that fails 20 times in a row is disabled. Read the Webhooks reference for the endpoints and payloads.
/docs/openapi.json.Reference for GET /v1/account on the Crayo API: plan, credit balances by type, storage usage and the rate limits that apply to your key.
API docsRegister https endpoints that receive signed POST deliveries when renders, AutoClip jobs, speech enhancements and tracker refreshes finish.
API docsDownload the Crayo API OpenAPI 3.1 document covering every endpoint, parameter, request body, response and error code, ready for Postman or client generators.
FeatureCall Crayo from your own product: auto clipping, AI voiceovers, images, and rendered short-form video over one REST API.
API docsImport media from a URL or upload bytes through a signed URL, then list, rename and delete the assets every other Crayo API endpoint reads from.
API docsGenerate images, icon sets, face swaps, narration and voice changes through the Crayo API. Every result is stored as an asset you can place in a project.
FAQs
Frequently asked questionsFrequent questionsContact our 24/7 support team for any concerns or inquiries.