API reference

Recipes

11 operations, 1 webhook. Base URL https://api.scarleta.ai. Select an operation to see its parameters, samples and errors.

Jump to an operation
DELETE/v1/recipe/{recipe_id}

Delete a recipe

Free and paid accounts
  • API key required
  • Free and paid accounts
  • No token cost

Permanently deletes a recipe saved by your account or team, together with its comments. This cannot be undone. A catalog recipe, another account's recipe, or one already deleted answers 404 not_found.

Cost. Free of charge.

RECIPE_ID="YOUR_RECIPE_ID"
curl -X DELETE "https://api.scarleta.ai/v1/recipe/$RECIPE_ID" \
  -H "Authorization: Bearer $SCARLETA_API_KEY"

Parameters

NameTypeRequiredDescription
recipe_idpathstringRequiredThe recipe id, for example `rec_4821_mix_check`. Ids are case-insensitive and are read in lower case. Allowed: at least 1 character.
Response fields
FieldTypeDescription
recipe_idstring
deletedtrue
Errors
StatusCodeDescription
401invalid_keyMissing, malformed, unknown or revoked API key.
404not_foundNo recipe of yours has this id (a catalog recipe, another account's recipe or one already deleted is answered the same way).
429rate_limit_exceededOver the account request budget for the hour. Wait for the `Retry-After` header, then retry.
503auth_unavailableTemporary platform condition; retry shortly.
Example responses
{
  "data": {
    "recipe_id": "rec_4821_mix_check",
    "deleted": true
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
  • 200 Success
  • 401 Missing, malformed, unknown or revoked API key.
  • 404 No recipe of yours has this id (a catalog recipe, another account's recipe or one already deleted is answered the same way).
  • 429 Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.
  • 503 Temporary platform condition; retry shortly.

Try it

Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.

Other error codes this operation can return: invalid_auth_format, invalid_key_format, missing_api_key, missing_auth, rate_limit_unavailable, unauthorized.

GET/v1/recipe/{recipe_id}/compare

Compare a fork with its source

Free and paid accounts
  • API key required
  • Free and paid accounts
  • No token cost

Shows which top-level fields of a fork differ from the recipe it was forked from, and how many steps each has. The recipe in the path must be a fork you can see, and its source must still be visible to you.

Cost. Free of charge.

RECIPE_ID="YOUR_RECIPE_ID"
curl "https://api.scarleta.ai/v1/recipe/$RECIPE_ID/compare" \
  -H "Authorization: Bearer $SCARLETA_API_KEY"

Parameters

NameTypeRequiredDescription
recipe_idpathstringRequiredThe recipe id, for example `rec_4821_mix_check`. Ids are case-insensitive and are read in lower case. Allowed: at least 1 character.
Response fields
FieldTypeDescription
successtrueAlways true.
fork_idstringThe fork you asked about.
source_idstringThe recipe it was forked from.
diffobject
diff.changedarray<object>Fields that differ. Empty when the fork is identical.
diff.changed[].fieldstringA recipe field: `recipe_name`, `user_intent`, `domain`, `ai_description`, `steps`, `budget` or `execution`.
diff.changed[].status"added" | "removed" | "changed"Whether the fork added the field, removed it or changed it.
diff.changed[].sourceanyThe value in the source.
diff.changed[].forkanyThe value in the fork.
diff.step_countobjectSteps in each recipe.
diff.step_count.sourceintegerAllowed: -9007199254740991 to 9007199254740991.
diff.step_count.forkintegerAllowed: -9007199254740991 to 9007199254740991.
Errors
StatusCodeDescription
400not_a_forkThe recipe in the path was not made by forking another.
401invalid_keyMissing, malformed, unknown or revoked API key.
404not_foundNo recipe with this id is visible to you: it does not exist, or it belongs to another account. Both are answered the same way. When the fork is visible but its source is not, the code is `source_not_found` instead.
429rate_limit_exceededOver the account request budget for the hour. Wait for the `Retry-After` header, then retry.
503auth_unavailableTemporary platform condition; retry shortly.
Example responses
{
  "data": {
    "success": true,
    "fork_id": "rec_3791_17925845289883",
    "source_id": "rec_4821_mix_check",
    "diff": {
      "changed": [
        {
          "field": "recipe_name",
          "status": "changed",
          "source": "Tempo check",
          "fork": "Tempo check (fork)"
        }
      ],
      "step_count": {
        "source": 1,
        "fork": 1
      }
    }
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
  • 200 Success
  • 400 The recipe in the path was not made by forking another.
  • 401 Missing, malformed, unknown or revoked API key.
  • 404 No recipe with this id is visible to you: it does not exist, or it belongs to another account. Both are answered the same way. When the fork is visible but its source is not, the code is `source_not_found` instead.
  • 429 Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.
  • 503 Temporary platform condition; retry shortly.

Try it

Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.

Other error codes this operation can return: invalid_auth_format, invalid_key_format, missing_api_key, missing_auth, rate_limit_unavailable, source_not_found, unauthorized.

POST/v1/recipe/{recipe_id}/fork

Fork a recipe

Free and paid accounts
  • API key required
  • Free and paid accounts
  • No token cost

Copies a recipe you can see (a catalog recipe or one of yours) into a new draft that belongs to you, and returns it with 201. The copy keeps a pointer to the source in forked_from; use GET /v1/recipe/{recipe_id}/compare to see how a fork has drifted. Without recipe_name the copy is named after the source with " (fork)" added. The response also carries internal bookkeeping fields; do not rely on them.

Cost. Free of charge.

RECIPE_ID="YOUR_RECIPE_ID"
curl -X POST "https://api.scarleta.ai/v1/recipe/$RECIPE_ID/fork" \
  -H "Authorization: Bearer $SCARLETA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipe_name": "Tempo check (fork)"
  }'

Parameters

NameTypeRequiredDescription
recipe_idpathstringRequiredThe recipe id, for example `rec_4821_mix_check`. Ids are case-insensitive and are read in lower case. Allowed: at least 1 character.

Request body

NameTypeRequiredDescription
recipe_namebodystringOptionalA name for the copy, at most 200 characters.
Response fields
FieldTypeDescription
successtrueAlways true.
recipe_idstringThe id of the new copy.
forked_fromstringThe id of the source.
forked_recipeobject
forked_recipe.recipe_idstringIdentifier of the recipe.
forked_recipe.recipe_namestring | nullThe recipe name.
forked_recipe.user_intentstringWhat the recipe is for.
forked_recipe.stepsarray<object>The ordered steps as stored.
forked_recipe.budgetanyBudget settings, or null.
forked_recipe.executionanyExecution settings, or null.
forked_recipe.tagsarray<string>Tags on the recipe.
forked_recipe.is_templatebooleanTrue for a catalog template recipe.
forked_recipe.usage_countintegerHow many times the recipe has been run. Allowed: -9007199254740991 to 9007199254740991.
forked_recipe.scopestringWho can see the recipe: `org-private` (your team) or `user-custom` (you).
forked_recipe.catalog_statusstring | null`draft`, `published`, or null for a recipe saved without a status.
forked_recipe.forked_fromstring | nullThe recipe this one was forked from, or null.
forked_recipe.ai_descriptionstring | nullA short description, or null.
forked_recipe.domainstring | nullThe subject area, or null.
forked_recipe.author_idstring | nullAuthor id for catalog recipes; null for yours.
forked_recipe.author_kindstring | nullAuthor kind for catalog recipes; null for yours.
forked_recipe.created_atintegerWhen the recipe was saved, in milliseconds since the Unix epoch. Allowed: -9007199254740991 to 9007199254740991.
forked_recipe.updated_atnumber | nullWhen it was last updated, or null.
forked_recipe.last_used_atnumber | nullWhen it was last run, or null.
Errors
StatusCodeDescription
400name_too_long`recipe_name` is too long.
401invalid_keyMissing, malformed, unknown or revoked API key.
404not_foundNo recipe with this id is visible to you: it does not exist, or it belongs to another account. Both are answered the same way.
413recipe_json_too_largeThe source recipe is over the size limit.
429rate_limit_exceededOver the account request budget for the hour. Wait for the `Retry-After` header, then retry.
503auth_unavailableTemporary platform condition; retry shortly.
Example responses
{
  "data": {
    "success": true,
    "recipe_id": "rec_3791_17925845289883",
    "forked_from": "rec_4821_mix_check",
    "forked_recipe": {
      "recipe_id": "rec_3791_17925845289883",
      "recipe_name": "Tempo check (fork)",
      "user_intent": "Estimate the tempo of a track",
      "steps": [
        {
          "step": 1,
          "tool": "tempo_analysis",
          "parameters": {}
        }
      ],
      "budget": null,
      "execution": null,
      "tags": [],
      "is_template": false,
      "usage_count": 0,
      "scope": "user-custom",
      "catalog_status": "draft",
      "forked_from": "rec_4821_mix_check",
      "ai_description": null,
      "domain": null,
      "author_id": null,
      "author_kind": null,
      "created_at": 1792586336723,
      "updated_at": null,
      "last_used_at": null
    }
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
  • 201 The new draft.
  • 400 `recipe_name` is too long.
  • 401 Missing, malformed, unknown or revoked API key.
  • 404 No recipe with this id is visible to you: it does not exist, or it belongs to another account. Both are answered the same way.
  • 413 The source recipe is over the size limit.
  • 429 Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.
  • 503 Temporary platform condition; retry shortly.

Try it

Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.

Other error codes this operation can return: invalid_auth_format, invalid_key_format, missing_api_key, missing_auth, rate_limit_unavailable, unauthorized.

POST/v1/recipe/{recipe_id}/unpublish

Unpublish a recipe

Free and paid accounts
  • API key required
  • Free and paid accounts
  • No token cost

Moves one of your recipes back to a draft. Only the status changes. You can unpublish recipes saved by your account or team; a catalog recipe or another account's recipe answers 404 not_found.

Cost. Free of charge.

RECIPE_ID="YOUR_RECIPE_ID"
curl -X POST "https://api.scarleta.ai/v1/recipe/$RECIPE_ID/unpublish" \
  -H "Authorization: Bearer $SCARLETA_API_KEY"

Parameters

NameTypeRequiredDescription
recipe_idpathstringRequiredThe recipe id, for example `rec_4821_mix_check`. Ids are case-insensitive and are read in lower case. Allowed: at least 1 character.
Response fields
FieldTypeDescription
recipe_idstring
catalog_status"draft"
Errors
StatusCodeDescription
401invalid_keyMissing, malformed, unknown or revoked API key.
404not_foundNo recipe of yours has this id (a catalog recipe or another account's recipe is answered the same way).
429rate_limit_exceededOver the account request budget for the hour. Wait for the `Retry-After` header, then retry.
503auth_unavailableTemporary platform condition; retry shortly.
Example responses
{
  "data": {
    "recipe_id": "rec_4821_mix_check",
    "catalog_status": "draft"
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
  • 200 Success
  • 401 Missing, malformed, unknown or revoked API key.
  • 404 No recipe of yours has this id (a catalog recipe or another account's recipe is answered the same way).
  • 429 Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.
  • 503 Temporary platform condition; retry shortly.

Try it

Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.

Other error codes this operation can return: invalid_auth_format, invalid_key_format, missing_api_key, missing_auth, rate_limit_unavailable, unauthorized.

POST/v1/recipe/approve

Record an approval or a rejection of a recipe

Free and paid accounts
  • API key required
  • Free and paid accounts
  • No token cost

Records that you approved or rejected a saved recipe. It changes nothing on the recipe itself and does not run it; it leaves a record that your own tools can use. With approved: true you may list modifications (fields you changed); their names are echoed in modifications_applied. With approved: false you may give a rejection_reason. modifications may be at most 102400 bytes once serialized.

Cost. Free of charge.

curl -X POST "https://api.scarleta.ai/v1/recipe/approve" \
  -H "Authorization: Bearer $SCARLETA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipe_id": "rec_4821_mix_check",
    "approved": true
  }'

Request body

NameTypeRequiredDescription
recipe_idbodystringRequiredThe id of a recipe in your account, for example `rec_4821_mix_check`. Allowed: at least 1 character.
approvedbodybooleanRequiredTrue to approve, false to reject. Must be a JSON boolean.
modificationsbodyobjectOptionalFields you changed before approving. Only used when `approved` is true.
rejection_reasonbodystringOptionalWhy you rejected it. Only kept when `approved` is false.
Response fields
FieldTypeDescription
successtrueAlways true.
recipe_idstringThe recipe the decision is about.
request_idstringIdentifier of this decision record.
approvedbooleanThe decision.
modifications_appliedarray<string>Names of the fields in `modifications`. Present when approved.
rejection_reasonstring | nullThe reason given, or null. Present when rejected.
Errors
StatusCodeDescription
400invalid_request`recipe_id` is missing, or `approved` is not a JSON boolean, or the body is not valid JSON (`invalid_json`).
401invalid_keyMissing, malformed, unknown or revoked API key.
404not_foundNo recipe with this id is visible to you.
413recipe_json_too_large`modifications` is over the size limit.
429rate_limit_exceededOver the account request budget for the hour. Wait for the `Retry-After` header, then retry.
503auth_unavailableTemporary platform condition; retry shortly.
Example responses
{
  "data": {
    "success": true,
    "recipe_id": "rec_4821_mix_check",
    "request_id": "0cf07e8d-6f86-47b3-8a35-35499a651571",
    "approved": true,
    "modifications_applied": []
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
  • 200 Success
  • 400 `recipe_id` is missing, or `approved` is not a JSON boolean, or the body is not valid JSON (`invalid_json`).
  • 401 Missing, malformed, unknown or revoked API key.
  • 404 No recipe with this id is visible to you.
  • 413 `modifications` is over the size limit.
  • 429 Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.
  • 503 Temporary platform condition; retry shortly.

Try it

Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.

Other error codes this operation can return: invalid_auth_format, invalid_json, invalid_key_format, missing_api_key, missing_auth, rate_limit_unavailable, unauthorized.

POST/v1/recipe/cancel

Set a proposed recipe aside in a conversation

Free and paid accounts
  • API key required
  • Free and paid accounts
  • No token cost

Declines a recipe that the assistant proposed in one of your conversations; a recipe that was never proposed in the conversation answers 404 recipe_not_found. The decline is saved durably in the conversation, and a run of that recipe that is still queued or in progress is stopped. Cancel is silent: it sends no reply and costs nothing. Calling it again for the same conversation and recipe answers 200 too and records nothing new. reason is optional. Leading and trailing spaces are removed, a reason that is only spaces counts as none, and only the first 500 characters of the rest are kept.

Cost. Free of charge. Cancel sends no reply and analyzes no audio.

curl -X POST "https://api.scarleta.ai/v1/recipe/cancel" \
  -H "Authorization: Bearer $SCARLETA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipe_id": "rec_4821_mix_check",
    "conversation_id": "3f9c1d2e-7b44-4c1a-8e0f-5a6b7c8d9e01",
    "reason": "Too slow."
  }'

Request body

NameTypeRequiredDescription
recipe_idbodystringRequiredThe id of the proposed recipe to set aside, at most 200 characters. Only letters, digits, `_`, `.`, `:`, `@` and `-` are allowed; other characters are rejected with 400 `invalid_request`. Allowed: 1 to 200 characters.
conversation_idbodystringRequiredThe conversation the recipe was proposed in. Must be a UUID of a conversation of yours.
reasonbodystringOptionalWhy you set it aside, in your own words. Only the first 500 characters are kept.
Response fields
FieldTypeDescription
successtrueAlways true.
recipe_idstringThe recipe set aside.
conversation_idstringThe conversation.
declinedtrueAlways true.
Errors
StatusCodeDescription
400invalid_request`recipe_id` is missing, empty, longer than 200 characters or contains characters outside letters, digits, `_`, `.`, `:`, `@` and `-`, `conversation_id` is missing or not a UUID, or the body is not valid JSON (`invalid_json`).
401invalid_keyMissing, malformed, unknown or revoked API key.
404not_foundThe conversation is not yours or does not exist (`not_found`), or the recipe was never proposed in this conversation (`recipe_not_found`).
429rate_limit_exceededOver the account request budget for the hour. Wait for the `Retry-After` header, then retry.
502decline_record_failedThe decline could not be saved. Nothing was cancelled; retry.
503auth_unavailableTemporary platform condition; retry shortly.
Example responses
{
  "data": {
    "success": true,
    "recipe_id": "rec_4821_mix_check",
    "conversation_id": "3f9c1d2e-7b44-4c1a-8e0f-5a6b7c8d9e01",
    "declined": true
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
  • 200 Success
  • 400 `recipe_id` is missing, empty, longer than 200 characters or contains characters outside letters, digits, `_`, `.`, `:`, `@` and `-`, `conversation_id` is missing or not a UUID, or the body is not valid JSON (`invalid_json`).
  • 401 Missing, malformed, unknown or revoked API key.
  • 404 The conversation is not yours or does not exist (`not_found`), or the recipe was never proposed in this conversation (`recipe_not_found`).
  • 429 Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.
  • 502 The decline could not be saved. Nothing was cancelled; retry.
  • 503 Temporary platform condition; retry shortly.

Try it

Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.

Other error codes this operation can return: invalid_auth_format, invalid_json, invalid_key_format, missing_api_key, missing_auth, rate_limit_unavailable, recipe_not_found, unauthorized.

POST/v1/recipe/execute

Run a recipe on an audio file

Free and paid accountsUses tokens
  • API key required
  • Free and paid accounts
  • Uses tokens

Starts a recipe on one audio file and answers 200 at once with a job_id; read progress with GET /v1/recipe/jobs/{job_id} or receive a recipe_completed webhook. Name the recipe with recipe_id (a saved recipe of yours or a catalog recipe) or send the whole recipe in recipe, never both. The cost is estimated before anything starts (a rough run time is shown in estimated_seconds, summed from typical timings of each step's tool; a tool with no measured timing counts as 45 seconds); an account whose balance cannot cover it gets 402 insufficient_balance with the estimate, the balance and the shortfall. audio_url must be a public http or https URL or a file in your own library; audio longer than 60 minutes is refused with 400 audio_too_long. Send conversation_id of one of your conversations to tie the run to it; repeating the same run for that conversation returns the existing job with idempotent: true, and a recipe you set aside with POST /v1/recipe/cancel answers status: declined with no job. Refusals use the standard error body; insufficient_balance (402) carries estimated_cost, balance, shortfall and audio_duration in error.details, and audio_too_long (400) carries audio_duration and max_duration. The top-level field budget is refused; set budgets in the recipe.

Cost. Each step is billed like the matching analysis of the audio: 1 token is 1 second of audio, at the rate of its capability. The estimate is checked against your balance before the run starts.

curl -X POST "https://api.scarleta.ai/v1/recipe/execute" \
  -H "Authorization: Bearer $SCARLETA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipe_id": "rec_4821_mix_check",
    "audio_url": "https://example.com/track-1.wav"
  }'

Request body

NameTypeRequiredDescription
audio_urlbodystringRequiredThe audio file to run the recipe on. Allowed: at least 1 character.
recipe_idbodystringOptionalThe id of a saved recipe, for example `rec_4821_mix_check`. Send this or `recipe`.
recipebodyobjectOptionalThe whole recipe, as accepted by `POST /v1/recipe/validate`, at most 102400 bytes once serialized. Send this or `recipe_id`.
conversation_idbodystringOptionalA conversation of yours to tie the run to. Must be a UUID; a value that is not one is ignored.
webhook_urlbodystringOptionalWhere to POST the `recipe_completed` event. An https URL that resolves to a public address, at most 4096 bytes.
Response fields
FieldTypeDescription
job_idstringIdentifier of the run. Absent only when `status` is `declined`.
statusstring`IN_QUEUE` for a new run; the current status for an existing one; `declined` for a recipe you set aside.
mode"recipe"Always `recipe`.
recipe_idstringThe recipe that runs.
audio_urlstringThe audio the run uses.
num_stepsintegerSteps in the recipe. Allowed: -9007199254740991 to 9007199254740991.
estimated_secondsintegerA rough run time in seconds. Allowed: -9007199254740991 to 9007199254740991.
idempotentbooleanTrue when this answer repeats an earlier identical run for the same conversation.
conversation_idstringPresent when `status` is `declined`.
declinedbooleanTrue when the recipe was set aside in the conversation; nothing ran.
Errors
StatusCodeDescription
400invalid_requestThe body is malformed or incomplete (`invalid_request`, `invalid_json`), the recipe fails validation (`invalid_recipe`, `invalid_recipe_parameters`), a URL is not acceptable (`invalid_audio_url`, `invalid_webhook_url`), or the audio cannot be used (`audio_too_long`, `unsupported_format`, `audio_processing_failed`).
401invalid_keyMissing, malformed, unknown or revoked API key.
402insufficient_balanceThe balance cannot cover the estimate. `error.details` carries `estimated_cost`, `balance`, `shortfall` and `audio_duration`. Nothing was charged.
403media_not_ownedThe audio file belongs to another account.
404not_foundNo recipe with this id is visible to you, or `conversation_id` names a conversation that is not yours. A file at `audio_url` that cannot be downloaded is 404 `audio_not_found`.
413recipe_json_too_large`recipe` (`recipe_json_too_large`) or `webhook_url` (`webhook_url_too_large`) is over its size limit.
429rate_limit_exceededOver the account request budget for the hour. Wait for the `Retry-After` header, then retry.
500workflow_binding_missingThe recipe runner is not configured in this environment. This is a deployment fault, not something to retry.
502workflow_start_failedThe run could not be started. Nothing was charged; retry.
503auth_unavailableTemporary platform condition; retry shortly.
Example responses
{
  "data": {
    "job_id": "recipe_9f3a1c7e52b4",
    "status": "IN_QUEUE",
    "mode": "recipe",
    "recipe_id": "rec_4821_mix_check",
    "audio_url": "https://example.com/track-1.wav",
    "num_steps": 1,
    "estimated_seconds": 45
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
  • 200 The run was accepted (or an identical earlier run was found).
  • 400 The body is malformed or incomplete (`invalid_request`, `invalid_json`), the recipe fails validation (`invalid_recipe`, `invalid_recipe_parameters`), a URL is not acceptable (`invalid_audio_url`, `invalid_webhook_url`), or the audio cannot be used (`audio_too_long`, `unsupported_format`, `audio_processing_failed`).
  • 401 Missing, malformed, unknown or revoked API key.
  • 402 The balance cannot cover the estimate. `error.details` carries `estimated_cost`, `balance`, `shortfall` and `audio_duration`. Nothing was charged.
  • 403 The audio file belongs to another account.
  • 404 No recipe with this id is visible to you, or `conversation_id` names a conversation that is not yours. A file at `audio_url` that cannot be downloaded is 404 `audio_not_found`.
  • 413 `recipe` (`recipe_json_too_large`) or `webhook_url` (`webhook_url_too_large`) is over its size limit.
  • 429 Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.
  • 500 The recipe runner is not configured in this environment. This is a deployment fault, not something to retry.
  • 502 The run could not be started. Nothing was charged; retry.
  • 503 Temporary platform condition; retry shortly.

Try it

Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.

Cost. Each step is billed like the matching analysis of the audio: 1 token is 1 second of audio, at the rate of its capability. The estimate is checked against your balance before the run starts.

Other error codes this operation can return: audio_not_found, audio_processing_failed, audio_too_long, invalid_audio_url, invalid_auth_format, invalid_json, invalid_key_format, invalid_recipe, invalid_recipe_parameters, invalid_webhook_url, missing_api_key, missing_auth, rate_limit_unavailable, unauthorized, unsupported_format, webhook_url_too_large, webhook_validation_unavailable.

POST/v1/recipe/generate

Generate a recipe from a request

Free and paid accounts
  • API key required
  • Free and paid accounts
  • No token cost

Describes in words what you want to find out and returns a recipe the planner built for it. Nothing is saved or run: review the recipe, change it if you like, then save it with POST /v1/recipe/save and run it. The recipe_id in the answer is only a suggestion and is not unique, so save the recipe under your own rec_ id. The call needs a token balance of at least 1 and does not debit tokens. It calls the planner, so it takes several seconds and can answer 503 planner_unavailable when the planner times out (the same status as auth_unavailable; read the code); retry later.

Cost. No tokens are debited, but the account needs a balance of at least 1 token.

curl -X POST "https://api.scarleta.ai/v1/recipe/generate" \
  -H "Authorization: Bearer $SCARLETA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "user_intent": "Estimate the tempo of my track",
    "budget_mode": "fast"
  }'

Request body

NameTypeRequiredDescription
user_intentbodystringRequiredWhat you want to find out, in words, at most 2000 characters. Allowed: 1 to 2000 characters.
budget_modebody"fast" | "balanced" | "quality"OptionalHow much work the plan may use: `fast` for the fewest, cheapest steps, `quality` for the most thorough.
audio_typebody"music" | "speech" | "mixed" | "unknown"OptionalWhat kind of audio the recipe is for.
max_costbodynumberOptionalA cost ceiling in tokens that the planner aims to stay under.
conversation_idbodystringOptionalA conversation of yours to attribute the planning to. Must be a UUID.
Response fields
FieldTypeDescription
successtrueAlways true.
recipeobjectThe recipe. The planner may add fields beyond the ones listed.
recipe.recipe_idstringA suggested id. Not unique.
recipe.user_intentstringYour request.
recipe.stepsarray<object>The planned steps. Each has a `step` number, a `tool` name and its `parameters`, and may carry `features`, `label` and `reason`.
recipe.estimated_costnumberThe planner's estimate of the cost in tokens.
recipe.budgetobjectThe budget the plan was made under.
recipe.rationalestringA short plain explanation of the plan.
steps_countintegerSteps in the recipe. Allowed: -9007199254740991 to 9007199254740991.
estimated_costnumberThe estimated cost in tokens; 0 when the planner gave none.
Errors
StatusCodeDescription
400invalid_request`user_intent` is missing, empty or too long, `conversation_id` is not a UUID, the planner could not produce a valid recipe (the message says why), or the body is not valid JSON (`invalid_json`).
401invalid_keyMissing, malformed, unknown or revoked API key.
402insufficient_balanceThe account has no token balance, or its tenant is frozen. Nothing was charged.
404not_found`conversation_id` names a conversation that is not yours or does not exist.
429rate_limit_exceededOver the account request budget for the hour. Wait for the `Retry-After` header, then retry.
503auth_unavailableTemporary platform condition; retry shortly.
Example responses
{
  "data": {
    "success": true,
    "recipe": {
      "recipe_id": "auto_generated_1712700000",
      "user_intent": "Estimate the tempo of my track",
      "steps": [
        {
          "step": 1,
          "tool": "tempo_analysis",
          "parameters": {
            "include_tempo": true
          },
          "features": [
            "tempo.bpm",
            "tempo.beat_count"
          ],
          "label": "Find the tempo"
        }
      ],
      "estimated_cost": 1,
      "budget": {
        "mode": "fast",
        "audio_type": "music",
        "max_cost": 5
      },
      "rationale": "One quick pass to hear the beat and give you the tempo."
    },
    "steps_count": 1,
    "estimated_cost": 1
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
  • 200 Success
  • 400 `user_intent` is missing, empty or too long, `conversation_id` is not a UUID, the planner could not produce a valid recipe (the message says why), or the body is not valid JSON (`invalid_json`).
  • 401 Missing, malformed, unknown or revoked API key.
  • 402 The account has no token balance, or its tenant is frozen. Nothing was charged.
  • 404 `conversation_id` names a conversation that is not yours or does not exist.
  • 429 Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.
  • 503 Temporary platform condition; retry shortly.

Try it

Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.

Other error codes this operation can return: invalid_auth_format, invalid_json, invalid_key_format, missing_api_key, missing_auth, planner_unavailable, rate_limit_unavailable, unauthorized.

GET/v1/recipe/jobs/{job_id}

Get a recipe run

Free and paid accounts
  • API key required
  • Free and paid accounts
  • No token cost

Returns the state of a run started with POST /v1/recipe/execute. Poll it until status is COMPLETED, FAILED, CANCELLED or TIMEOUT; results is filled in only once the run has ended. Only recipe runs (ids that start with recipe_) are read here; use GET /v1/analyze/{job_id} for analyses. completed_steps and num_steps count the steps that finished and the steps in the recipe (num_steps is 0 until the run has ended). When you gave a webhook_url, webhook_delivery_status shows how the recipe_completed delivery went: in_progress, delivered, failed, or unconfirmed; it is null when there is no webhook or the run has not ended. It describes only that per-request webhook_url: addresses registered with POST /v1/webhooks are retried the same way, but their outcome is not shown in this field.

Cost. Free of charge.

JOB_ID="YOUR_JOB_ID"
curl "https://api.scarleta.ai/v1/recipe/jobs/$JOB_ID" \
  -H "Authorization: Bearer $SCARLETA_API_KEY"

Parameters

NameTypeRequiredDescription
job_idpathstringRequiredThe `job_id` from the execute answer, for example `recipe_9f3a1c7e52b4`. Allowed: at least 1 character.
Response fields
FieldTypeDescription
job_idstringIdentifier of the run.
statusstring | null`IN_QUEUE`, `IN_PROGRESS`, `COMPLETED`, `FAILED`, `CANCELLED` or `TIMEOUT`.
mode"recipe"Always `recipe`.
recipe_idstring | nullThe recipe that ran; null until the run has ended.
audio_urlstring | nullThe audio the run used.
num_stepsintegerSteps in the recipe; 0 until the run has ended. Allowed: -9007199254740991 to 9007199254740991.
completed_stepsintegerSteps that finished. Allowed: -9007199254740991 to 9007199254740991.
resultsobject | nullThe outcome of the run, once it has ended: the recipe, its steps and their results. Null while the run is queued or in progress, and for `TIMEOUT`.
errorstring | nullWhy the run failed, or null.
error_codestring | nullA short code for the failure, or null.
started_atnumber | nullWhen the run started, in milliseconds since the Unix epoch, or null.
completed_atnumber | nullWhen the run ended, in milliseconds since the Unix epoch, or null.
webhook_delivery_statusstring | nullState of the `recipe_completed` delivery to the per-request `webhook_url` only (registered addresses are not reflected here), or null.
webhook_last_attempt_atnumber | nullWhen the last delivery attempt started, in milliseconds since the Unix epoch, or null.
Errors
StatusCodeDescription
401invalid_keyMissing, malformed, unknown or revoked API key.
404not_foundNo recipe run with this id belongs to your account, or the id does not start with `recipe_`.
429rate_limit_exceededOver the account request budget for the hour. Wait for the `Retry-After` header, then retry.
503auth_unavailableTemporary platform condition; retry shortly.
Example responses
{
  "data": {
    "job_id": "recipe_9f3a1c7e52b4",
    "status": "COMPLETED",
    "mode": "recipe",
    "recipe_id": "rec_4821_mix_check",
    "audio_url": "https://example.com/track-1.wav",
    "num_steps": 1,
    "completed_steps": 1,
    "results": {
      "status": "success",
      "recipe_id": "rec_4821_mix_check",
      "step_count": 1,
      "response": null,
      "conversation_id": null
    },
    "error": null,
    "error_code": null,
    "started_at": 1792586336723,
    "completed_at": 1792586348723,
    "webhook_delivery_status": null,
    "webhook_last_attempt_at": null
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
  • 200 Success
  • 401 Missing, malformed, unknown or revoked API key.
  • 404 No recipe run with this id belongs to your account, or the id does not start with `recipe_`.
  • 429 Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.
  • 503 Temporary platform condition; retry shortly.

Try it

Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.

Other error codes this operation can return: invalid_auth_format, invalid_key_format, missing_api_key, missing_auth, rate_limit_unavailable, unauthorized.

POST/v1/recipe/save

Save a recipe

Free and paid accounts
  • API key required
  • Free and paid accounts
  • No token cost

Saves a recipe to your account and returns it. A recipe saved with recipe_id of an existing recipe of yours replaces it; one saved under another account's id answers 404 not_found. Without catalog_status or with published, the recipe must pass validation and recipe.recipe_id is required. With catalog_status: draft validation is skipped so you can save work in progress, and a recipe with no recipe_id gets one made for you. catalog_status can only be draft or published, and cannot be set on a template recipe (403 forbidden). The response also carries internal bookkeeping fields; do not rely on them.

Cost. Free of charge.

curl -X POST "https://api.scarleta.ai/v1/recipe/save" \
  -H "Authorization: Bearer $SCARLETA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipe": {
      "recipe_id": "rec_4821_mix_check",
      "user_intent": "Estimate the tempo of a track",
      "steps": [
        {
          "step": 1,
          "tool": "tempo_analysis",
          "parameters": {}
        }
      ]
    },
    "recipe_name": "Tempo check",
    "catalog_status": "published"
  }'

Request body

NameTypeRequiredDescription
recipebodyobjectRequiredThe recipe. At most 102400 bytes once serialized.
recipe.recipe_idbodystringOptionalThe recipe id: letters, digits, underscore and hyphen, at most 128 characters. Required to validate. To save it for later use it must look like `rec_` + four digits + `_` + a name (for example `rec_0001_speech_quality`); a draft save may leave it out.
recipe.user_intentbodystringOptionalWhat the recipe is for, in words.
recipe.stepsbodyarray<object>OptionalThe ordered steps, from 1 to 10.
recipe.steps[].stepbodyintegerRequiredThe step number, starting at 1. Numbers must be unique. Allowed: -9007199254740991 to 9007199254740991.
recipe.steps[].toolbodystringRequiredThe capability to run, for example `tempo_analysis`. An unknown name is refused and the error lists the valid ones.
recipe.steps[].parametersbodyobjectOptionalSettings for the step. A plain object; leave it out for none.
recipe.steps[].featuresbodyarray<string>OptionalFeature names to compute, where the capability takes them.
recipe.steps[].depends_onbodyarray<integer>OptionalEarlier step numbers this step needs the output of.
recipe.steps[].timeout_msbodyintegerOptionalHow long the step may run, in milliseconds, from 1000 to 300000.
recipe.budgetbodyobjectOptionalOptional budget settings: `mode` (`fast`, `balanced` or `quality`) and `compute` (`cpu_only` or `gpu_allowed`).
recipe.executionbodyobjectOptionalOptional execution settings.
recipe_namebodystringOptionalA name, at most 200 characters.
tagsbodyarray<string>OptionalTags to keep with the recipe.
is_templatebodybooleanOptionalSave as a template recipe. Defaults to false.
catalog_statusbody"draft" | "published"OptionalWhether this is a work-in-progress draft or a published recipe. Leave it out for neither.
Response fields
FieldTypeDescription
successtrueAlways true.
recipe_idstringThe id the recipe was saved under.
saved_recipeobject
saved_recipe.recipe_idstringIdentifier of the recipe.
saved_recipe.recipe_namestring | nullThe recipe name.
saved_recipe.user_intentstringWhat the recipe is for.
saved_recipe.stepsarray<object>The ordered steps as stored.
saved_recipe.budgetanyBudget settings, or null.
saved_recipe.executionanyExecution settings, or null.
saved_recipe.tagsarray<string>Tags on the recipe.
saved_recipe.is_templatebooleanTrue for a catalog template recipe.
saved_recipe.usage_countintegerHow many times the recipe has been run. Allowed: -9007199254740991 to 9007199254740991.
saved_recipe.scopestringWho can see the recipe: `org-private` (your team) or `user-custom` (you).
saved_recipe.catalog_statusstring | null`draft`, `published`, or null for a recipe saved without a status.
saved_recipe.forked_fromstring | nullThe recipe this one was forked from, or null.
saved_recipe.ai_descriptionstring | nullA short description, or null.
saved_recipe.domainstring | nullThe subject area, or null.
saved_recipe.author_idstring | nullAuthor id for catalog recipes; null for yours.
saved_recipe.author_kindstring | nullAuthor kind for catalog recipes; null for yours.
saved_recipe.created_atintegerWhen the recipe was saved, in milliseconds since the Unix epoch. Allowed: -9007199254740991 to 9007199254740991.
saved_recipe.updated_atnumber | nullWhen it was last updated, or null.
saved_recipe.last_used_atnumber | nullWhen it was last run, or null.
Errors
StatusCodeDescription
400invalid_requestThe recipe is missing or empty, failed validation, or `catalog_status` is not allowed (`invalid_request`); `recipe_id` has the wrong format (`invalid_recipe_id`); or `recipe_name` is too long (`name_too_long`).
401invalid_keyMissing, malformed, unknown or revoked API key.
403forbidden`catalog_status` was set on a template recipe.
404not_found`recipe.recipe_id` names a recipe that belongs to another account.
413recipe_json_too_largeThe recipe is over the size limit.
429rate_limit_exceededOver the account request budget for the hour. Wait for the `Retry-After` header, then retry.
503auth_unavailableTemporary platform condition; retry shortly.
Example responses
{
  "data": {
    "success": true,
    "recipe_id": "rec_4821_mix_check",
    "saved_recipe": {
      "recipe_id": "rec_4821_mix_check",
      "recipe_name": "Tempo check",
      "user_intent": "Estimate the tempo of a track",
      "steps": [
        {
          "step": 1,
          "tool": "tempo_analysis",
          "parameters": {}
        }
      ],
      "budget": null,
      "execution": null,
      "tags": [],
      "is_template": false,
      "usage_count": 0,
      "scope": "user-custom",
      "catalog_status": "published",
      "forked_from": null,
      "ai_description": null,
      "domain": null,
      "author_id": null,
      "author_kind": null,
      "created_at": 1792586336723,
      "updated_at": null,
      "last_used_at": null
    }
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
  • 200 Saved.
  • 400 The recipe is missing or empty, failed validation, or `catalog_status` is not allowed (`invalid_request`); `recipe_id` has the wrong format (`invalid_recipe_id`); or `recipe_name` is too long (`name_too_long`).
  • 401 Missing, malformed, unknown or revoked API key.
  • 403 `catalog_status` was set on a template recipe.
  • 404 `recipe.recipe_id` names a recipe that belongs to another account.
  • 413 The recipe is over the size limit.
  • 429 Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.
  • 503 Temporary platform condition; retry shortly.

Try it

Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.

Other error codes this operation can return: invalid_auth_format, invalid_json, invalid_key_format, invalid_recipe_id, missing_api_key, missing_auth, name_too_long, rate_limit_unavailable, save_failed, unauthorized.

POST/v1/recipe/validate

Validate a recipe

Free and paid accounts
  • API key required
  • Free and paid accounts
  • No token cost

Checks a recipe without saving or running it. A valid recipe answers { valid: true, steps_count }. An invalid one answers 400 invalid_request and the message lists every problem, one per line. Run it before saving or running a recipe you built by hand. The recipe may be at most 102400 bytes once serialized.

Cost. Free of charge.

curl -X POST "https://api.scarleta.ai/v1/recipe/validate" \
  -H "Authorization: Bearer $SCARLETA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipe": {
      "recipe_id": "rec_4821_mix_check",
      "user_intent": "Estimate the tempo of a track",
      "steps": [
        {
          "step": 1,
          "tool": "tempo_analysis",
          "parameters": {}
        }
      ]
    }
  }'

Request body

NameTypeRequiredDescription
recipebodyobjectRequired
recipe.recipe_idbodystringRequiredThe recipe id: letters, digits, underscore and hyphen, at most 128 characters. Required to validate. To save it for later use it must look like `rec_` + four digits + `_` + a name (for example `rec_0001_speech_quality`); a draft save may leave it out.
recipe.user_intentbodystringOptionalWhat the recipe is for, in words.
recipe.stepsbodyarray<object>RequiredThe ordered steps, from 1 to 10.
recipe.steps[].stepbodyintegerRequiredThe step number, starting at 1. Numbers must be unique. Allowed: -9007199254740991 to 9007199254740991.
recipe.steps[].toolbodystringRequiredThe capability to run, for example `tempo_analysis`. An unknown name is refused and the error lists the valid ones.
recipe.steps[].parametersbodyobjectOptionalSettings for the step. A plain object; leave it out for none.
recipe.steps[].featuresbodyarray<string>OptionalFeature names to compute, where the capability takes them.
recipe.steps[].depends_onbodyarray<integer>OptionalEarlier step numbers this step needs the output of.
recipe.steps[].timeout_msbodyintegerOptionalHow long the step may run, in milliseconds, from 1000 to 300000.
recipe.budgetbodyobjectOptionalOptional budget settings: `mode` (`fast`, `balanced` or `quality`) and `compute` (`cpu_only` or `gpu_allowed`).
recipe.executionbodyobjectOptionalOptional execution settings.
Response fields
FieldTypeDescription
validtrue
steps_countintegerSteps in the recipe. Allowed: -9007199254740991 to 9007199254740991.
Errors
StatusCodeDescription
400invalid_requestThe recipe is missing or not an object (`Error: recipe is required`), or it failed validation (the message lists the problems), or the body is not valid JSON (`invalid_json`).
401invalid_keyMissing, malformed, unknown or revoked API key.
413recipe_json_too_largeThe recipe is over the size limit.
429rate_limit_exceededOver the account request budget for the hour. Wait for the `Retry-After` header, then retry.
503auth_unavailableTemporary platform condition; retry shortly.
Example responses
{
  "data": {
    "valid": true,
    "steps_count": 1
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
  • 200 Success
  • 400 The recipe is missing or not an object (`Error: recipe is required`), or it failed validation (the message lists the problems), or the body is not valid JSON (`invalid_json`).
  • 401 Missing, malformed, unknown or revoked API key.
  • 413 The recipe is over the size limit.
  • 429 Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.
  • 503 Temporary platform condition; retry shortly.

Try it

Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.

Other error codes this operation can return: invalid_auth_format, invalid_json, invalid_key_format, missing_api_key, missing_auth, rate_limit_unavailable, unauthorized.

EVENTrecipe_completed

Webhook: Recipe run completed

Sent by Scarleta

Sent when a run finishes, whether it completed or failed: to the webhook_url of the run, if it has one, and to every address registered with POST /v1/webhooks. A run that is cancelled, or that stalls and is stopped by Scarleta's automatic recovery, sends no recipe_completed; read GET /v1/recipe/jobs/{job_id} for its final status. The body is a JSON object with exactly the fields below. Each delivery carries X-Scarleta-Timestamp (Unix seconds) and X-Scarleta-Signature (v1= followed by the lowercase hex HMAC-SHA256 of <timestamp>.<raw body>, keyed with your signing secret from GET /v1/webhooks/signing-secret). Reject deliveries whose timestamp is more than 300 seconds from your clock. For one day after a rotation a delivery also carries X-Scarleta-Signature-Previous, signed with the previous secret; a receiver that has not switched to the new secret yet can verify that header with its old secret. Addresses registered with POST /v1/webhooks receive this event too, signed the same way; an address identical to the webhook_url is delivered once.

Your endpoint must answer with a 2xx status within 10 seconds. Scarleta makes up to 3 attempts, waiting 2 s and 4 s before the second and third; redirects are not followed. Targets that are not public https endpoints are never called. A run starts one delivery sequence to its webhook_url and never a second one, but inside that sequence an attempt that timed out or got a non-2xx answer is sent again with the same body, and the earlier attempt may already have reached you: de-duplicate by job_id. Registered addresses are delivered at least once, on a best-effort basis: a failed delivery to a registered address can also be sent again when the same completion is replayed, so de-duplicate by job_id there too. webhook_delivery_status on the job shows the outcome of the delivery to its webhook_url only. Registered addresses are retried the same way, but their outcome is not shown in that field.

Set by the webhook_url field of Run a recipe on an audio file.

Payload

FieldTypeDescription
event"recipe_completed"
job_idstringThe run that ended.
recipe_idstring | nullThe recipe that ran; null if the run ended before the recipe was read.
status"completed" | "failed"How the run ended.
audio_urlstringThe audio the run used.
num_stepsintegerSteps in the recipe. Allowed: -9007199254740991 to 9007199254740991.
completed_stepsintegerSteps that finished. Allowed: -9007199254740991 to 9007199254740991.
errorstring | nullWhy the run failed, or null.
completed_atnumberWhen the run ended, in milliseconds since the Unix epoch.

Example payload

{
  "event": "recipe_completed",
  "job_id": "recipe_9f3a1c7e52b4",
  "recipe_id": "rec_4821_mix_check",
  "status": "completed",
  "audio_url": "https://example.com/track-1.wav",
  "num_steps": 1,
  "completed_steps": 1,
  "error": null,
  "completed_at": 1792586348723
}