OmnAPI Webhook Events
OmnAPI emits webhooks for three layers of lifecycle:
- Task-level:
task.completed,task.failed,task.cancelled— fired once per task at terminal state. - Stage-level:
task.stage.started,task.stage.completed,task.stage.failed— emitted for named milestones in supported long-running tasks. Use these events for progress bars or operational dashboards without aggressive polling. - Product-level: product-specific events that summarize a resource outcome,
such as
mv.readyandmv.failedfor Music Video jobs.
All event layers fire to the same destination URL. The event type is delivered in the
X-Webhook-Event HTTP header. Terminal task bodies are flat public Task
descriptors. Stage bodies contain only taskId plus a stage snapshot. MV
product events also include a top-level event field with the same value as
the header for product-level routing.
Subscribing
Section titled “Subscribing”Pass webhookUrl in the task creation request:
curl -X POST https://api.omnapi.com/api/v1/suno/songs \ -H "x-api-key: sk_live_..." \ -H "Idempotency-Key: webhook-song-001" \ -H "Content-Type: application/json" \ -d '{ "mode": "simple", "prompt": "upbeat lo-fi", "config": { "webhookUrl": "https://yourapp.com/webhooks/omnapi" } }'The dashboard also lets you set a default destination for account-level task
events. Per-task webhookUrl takes precedence for that one request.
Delivery headers
Section titled “Delivery headers”For every event, read the type from X-Webhook-Event. There is no outer
{ event, task } envelope for task or stage events:
POST /your/webhook HTTP/1.1Content-Type: application/jsonX-Webhook-Event: task.completedEvery delivery includes these headers:
| Header | Meaning |
|---|---|
X-Webhook-Id | Stable event-delivery ID. It does not change across retries; use it as the primary deduplication key. |
X-Webhook-Event | Event type such as task.completed or mv.ready. |
X-Webhook-Timestamp | ISO timestamp generated for this delivery attempt. It is metadata and is not part of the body-only HMAC. |
X-Webhook-Attempt | One-based delivery attempt number. |
X-Webhook-Signature | Optional sha256=<hex> HMAC over the exact raw body when a webhook secret is configured. |
Task-level events
Section titled “Task-level events”Terminal task event bodies use the same customer-safe shape as
GET /api/v1/tasks/{taskId}:
{ "taskId": "task_01H...", "status": "COMPLETED", "creditsRequired": 250, "creditsCharged": 250, "refunded": false, "retryable": false, "createdAt": "2026-08-08T10:00:00.000Z", "updatedAt": "2026-08-08T10:03:07.432Z", "processingStartedAt": "2026-08-08T10:00:01.000Z", "processingCompletedAt": "2026-08-08T10:03:07.432Z", "processingDuration": 186432, "processingDurationText": "3.1m", "inputParameters": { "prompt": "..." }, "outputResults": { "result": "..." }, "resources": [], "warningCodes": []}task.completed
Section titled “task.completed”Fired once when a task transitions to COMPLETED. task.outputResults
carries the final payload, creditsCharged reflects the actual cost
(may be less than creditsRequired after refunds or partial output handling).
task.failed
Section titled “task.failed”Fired once on FAILED (X-Webhook-Event: task.failed). The flat body adds:
{ "taskId": "task_01H...", "status": "FAILED", "errorCode": "MV_TOO_MANY_FAILED_SCENES", "errorMessage": "5/8 scene images failed (threshold 0.3)"}Any eligible refund to your credit balance is issued with the status transition. By the time you receive the event, that settlement is already complete.
task.cancelled
Section titled “task.cancelled”Fired when a task is cancelled before it completes. Same envelope as
task.failed minus errorCode/errorMessage. Refund also atomic.
Stage-level events
Section titled “Stage-level events”Supported long-running tasks may emit named stage events. A stage emits
started once, followed by either completed or a final failed. An internal
retry does not emit another started event or an intermediate failed
webhook.
Stage payload
Section titled “Stage payload”The event type (e.g. task.stage.completed) is in the X-Webhook-Event header.
The body contains taskId and a top-level stage block; it is not a full Task
descriptor and has no top-level Task status:
{ "taskId": "task_01H...", "stage": { "name": "scenes", "description": "Plan scenes", "status": "completed", "startedAt": "...", "completedAt": "...", "durationMs": 47213, "attempt": 1, "maxAttempts": 2, "payload": { "sceneCount": 8, "genre": "rap", "mvParadigm": "performance" } }}stage.payload is stage-specific. Treat unknown keys as metadata and do not
build business-critical logic around fields that are not documented for your
endpoint.
task.stage.failed
Section titled “task.stage.failed”task.stage.failed is emitted only after the stage exhausts its configured
attempts:
{ "taskId": "task_01H...", "stage": { "name": "scenes", "description": "Plan scenes", "status": "failed", "startedAt": "2026-08-08T10:00:01.000Z", "completedAt": "2026-08-08T10:02:01.000Z", "durationMs": 120000, "attempt": 2, "maxAttempts": 2, "error": { "code": "STAGE_SCENES_FAILED", "message": "stage timed out" } }}A final stage failure does not always mean the Task fails because some stages are optional. Use the later task-level terminal event, or poll the Task, as the authoritative outcome.
MV Studio storyboard stage timeline
Section titled “MV Studio storyboard stage timeline”Studio storyboard is a public Beta workflow under POST /api/v1/mv with
mode="studio". Storyboard tasks may emit this sequence:
| # | Stage name | Typical duration |
|---|---|---|
| 1 | resolve-song | Usually <15s |
| 2 | analyze | Usually <5s |
| 3 | emotion | 5-30s |
| 4 | concept | 5-30s |
| 5 | character-anchor | 15-40s when a character anchor is needed |
| 6 | narrative | 5-30s |
| 7 | scenes | 10-60s |
| 8 | scene-images | 60-240s |
Followed by the task-level task.completed. Total wall-clock 3-10min for a
typical 60-second song.
MV scene render stage timeline
Section titled “MV scene render stage timeline”Scene-render tasks usually complete with task-level events only.
MV finalize stage timeline
Section titled “MV finalize stage timeline”Finalize tasks usually complete with task-level events only.
MV product events
Section titled “MV product events”MV create and finalize tasks may emit product-level events after the MV resource state is known.
| Event | When it fires |
|---|---|
mv.ready | An MV task produced a ready MV resource or final video reference. |
mv.failed | An MV task failed and the MV resource cannot advance without a new request. |
The event type is still delivered in X-Webhook-Event. The JSON body includes
the same event value and MV-specific routing fields:
POST /your/webhook HTTP/1.1Content-Type: application/jsonX-Webhook-Event: mv.ready{ "event": "mv.ready", "taskId": "task_01H...", "status": "COMPLETED", "mode": "fast", "mvId": "mv_01H...", "finalMvId": "final_01H...", "finalStatus": "READY", "deliveryStatus": "ready", "viewUrl": "/api/v1/mv/mv_01H...", "finalUrl": "/api/v1/mv/mv_01H.../final"}Treat missing optional fields as “not available yet” rather than as a schema
error. For example, finalUrl is only present when a final MP4 can be requested.
Ordering + delivery guarantees
Section titled “Ordering + delivery guarantees”| Guarantee | Strength |
|---|---|
| HTTP arrival order, including stage boundaries from one task | No guarantee. Delivery jobs run independently and retries can overtake later events. |
| Across tasks: events arrive in any order | No guarantee. |
| Exactly-once delivery | At-least-once — retries can re-deliver. Dedupe by the stable X-Webhook-Id. |
OmnAPI makes one initial webhook delivery attempt and then up to 5 retries with backoff 10s → 20s → 40s → 10min → 30min. HTTP 2xx is treated as success. After the final attempt the delivery is visible in the dashboard’s Webhook Events page where you can manually re-trigger.
Securing endpoints
Section titled “Securing endpoints”Use HTTPS webhook URLs on domains you control. Verify signatures when a webhook
secret is configured, dedupe on X-Webhook-Id, and reject duplicate deliveries
in your application. For higher-security
deployments, combine signature verification with your own allowlist or gateway
rules.
If you configure a webhook secret, OmnAPI sends
X-Webhook-Signature: sha256=<hex> where the hex value is HMAC-SHA256 over the
raw request body. A minimal Node receiver is available here:
Download webhook-receiver-node.ts
Best practices
Section titled “Best practices”- Acknowledge fast. Respond 2xx within 10s, then continue heavier work asynchronously in your application.
- Dedupe by
X-Webhook-Id. The value remains stable across every delivery attempt for one event. - Use task-level events for billing logic. Billing settles at task-level; stage events are for UX and observability.
- Subscribe to
task.stage.completed, nottask.stage.startedunless you’re building a live progress bar. Started events are noisy. - Read
X-Webhook-Eventfirst. Task and stage bodies do not include aneventfield. MV product bodies include it as a convenience, but the header is still the routing source of truth.
See also
Section titled “See also”- The Task Model — task lifecycle, status enum, config, polling
- MV API — the canonical multi-stage flow
- Dashboard → Webhooks — see delivery history + manually retry failed events