docs / resources / webhooks

Webhooks

Instead of polling, let SongAPI POST the result to you. When a generation reaches a terminal state we send a generation.complete or generation.failed event to:

  • the webhook_url you passed on that request, if any, and
  • every enabled endpoint registered on your dashboard that subscribes to the event type.

## Event payload

POST to your endpointjson
{
  "id": "evt_k8PqXw4RtY7NcAbD",
  "type": "generation.complete",
  "created": 1784692061,
  "livemode": true,
  "data": {
    "generation": { … full generation object, incl. clips … }
  }
}

data.generation is the same generation object that GET /v1/generations/:id returns. livemode is false for sandbox generations — sandbox webhooks fire like live ones, so you can test end to end for free.

## Headers & signature

Every delivery is signed with your account's webhook secret (whsec_…, on the dashboard):

request headers
content-type: application/json
user-agent: SongAPI-Webhooks/1.0
songapi-signature: t=1784692061,v1=5257a869e7…

v1 is the hex HMAC-SHA256 of "{t}.{raw body}" keyed with your secret. Verify before trusting the payload:

verify.jsnode
import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody, header, secret) {
  const { t, v1 } = Object.fromEntries(
    header.split(",").map((p) => p.split("="))
  );
  const expected = createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest("hex");
  return timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}

Reject stale timestamps (e.g. older than 5 minutes) to guard against replays. Compute the HMAC over the raw request body, before any JSON parsing.

## Delivery behavior

  • Endpoints must be HTTPS URLs and respond within 5 seconds; redirects are not followed.
  • Respond with any 2xx quickly and do your processing async.
  • Webhooks are a convenience, not the source of truth: if a delivery fails, the generation is unaffected — you can always fetch it via GET /v1/generations/:id. Delivery results for registered endpoints are visible on the dashboard.
  • You can fire a test event to any registered endpoint from the dashboard.