Back to introduction

Webhooks

Don't poll. We call you. When a batch or a single recipe finishes, Scarleta sends an HTTP POST to your endpoint with the completion event. Give us the URL when you submit the work. There is nothing to configure ahead of time.

How you receive a webhook

You provide the destination inline, as the webhook_url field in the API request payload. When the job reaches a terminal state, we POST the event to exactly that URL. There is no separate step and nothing stored on our side to manage. The URL travels with the request that starts the work.

curl -X POST https://api.scarleta.ai/v1/batch \
  -H "Authorization: Bearer $SCARLETA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipe_id": "rec_0007_stem_split",
    "audio_urls": ["https://example.com/track-1.wav"],
    "webhook_url": "https://your-app.com/hooks/scarleta"
  }'

The batch_completed event

batch_completed

When a batch finishes, we POST a JSON body with exactly these nine fields, in this order:

#FieldTypeDescription
1eventstringAlways "batch_completed" for a batch webhook.
2batch_idstring (UUID)The batch this event is for.
3statusstringTerminal batch state: completed, failed, or cancelled.
4total_itemsintegerTotal items submitted in the batch.
5completed_itemsintegerItems that finished successfully.
6failed_itemsintegerItems that failed after retries.
7cancelled_itemsintegerItems cancelled before they ran.
8actual_total_costnumberTotal tokens actually charged across the batch.
9completed_atstring (ISO 8601)When the batch reached its terminal state.

Example payload

{
  "event": "batch_completed",
  "batch_id": "b1a2c3d4-e5f6-4789-a0b1-c2d3e4f5a6b7",
  "status": "completed",
  "total_items": 2,
  "completed_items": 2,
  "failed_items": 0,
  "cancelled_items": 0,
  "actual_total_cost": 184,
  "completed_at": "2026-08-08T17:42:09.512Z"
}

Single recipes

recipe_completed

A single recipe execution has its own completion counterpart, recipe_completed. It is delivered the same way, to the webhook_url you pass in the request payload, with the same delivery guarantees below.

Delivery guarantees

Unsigned. We don't sign the payload. The only secret involved is whatever you embed in the webhook_url itself (for example a hard-to-guess path or a token query parameter). Keep that URL private and treat it as the shared secret.
SSRF-guarded. Private and loopback targets are blocked, no POST is sent to them, and redirects are not followed. Your endpoint must be a public HTTPS URL.
Three delivery attempts. If your endpoint doesn't accept the POST, we retry with a backoff of 2 seconds, then 4 seconds, then stop.
Idempotent. A replay never causes a double-POST. Deliver-once semantics mean you can safely process each event on batch_id.

Next steps

Webhooks · Scarleta API | Scarleta