Suno API webhooks, done right
Music generation takes 1–3 minutes, so you have two ways to find out a job finished: poll GET /api/jobs/{id} on a loop, or pass a callback_url and let the API push you a webhook the moment it’s done. Webhooks are cheaper and lower-latency — but only if you verify them. Here’s how to do it properly.
The signature scheme
Tunova signs every webhook. Two headers come with the POST:
X-Webhook-Timestamp— unix seconds when we sent it.X-Webhook-Signature—sha256=<hex>, the HMAC-SHA256 of<timestamp>.<raw-body>keyed with yourwhsec_…secret (view/rotate it on the dashboard’s API-keys page).
Two rules that trip people up: (1) verify against the raw request body, before any JSON parsing re-serializes it; (2) use a constant-time comparison so you don’t leak timing information.
Verify it — Node
Verify it — Python
Timestamp tolerance (replay protection)
Reject deliveries whose timestamp is more than a few minutes old (300s above). That stops an attacker from replaying a captured valid webhook later.
Idempotency & retries
We retry delivery on non-2xx, so your handler must be idempotent: key on the job_id and ignore a repeat you’ve already processed. Ack fast (return 200 immediately), then do the slow work — audio download, DB writes — out of band, so a slow handler doesn’t look like a failure and trigger a retry.
Don’t want to write this?
The Tunova SDKs ship the verifier above as verifyWebhook (Node) / Tunova.verify_webhook (Python) — one call. And because Tunova is billed only on success, a status: "failed" webhook means the tokens already refunded themselves; your handler just logs it. See the quickstart to get a key (50 free tokens, no card).
Tunova is an independent service, not affiliated with or endorsed by Suno.