Guides
Webhooks
ClipSonar POSTs signed JSON to your HTTPS endpoints when subscribed events occur. Register endpoints in Settings → API access or via POST /webhooks.
Delivery
- Method:
POSTwithContent-Type: application/json - Signature header:
X-ClipSonar-Signature(HMAC-SHA256 hex of the raw body, using yourwhsec_…secret) - Failed deliveries are retried with backoff. Respond with 2xx to acknowledge.
- Signing secrets use the
whsec_…prefix. You can copy them anytime from Settings → API access.
Envelope
Every delivery uses the same outer shape:
{
"event": "creator.ready",
"created_at": "2026-08-04T14:00:00.000Z",
"workspace_id": "grp_1111-2222-3333-4444",
"data": {
"creator_id": "354bb8ac-815d-4db1-8db8-ddf76c0f9494",
"job_id": "82fde0d4-1111-2222-3333-444455556666"
}
}event: event namecreated_at: ISO timestamp when ClipSonar emitted the eventworkspace_id: group scope when applicable, otherwisenulldata: event-specific payload
Events
creator.created
Right after POST /creators accepts a new creator job.
{
"creator_id": "…",
"job_id": "…",
"external_user_id": null,
"metadata": null
}creator.ready
Creator ingest, analysis, and insights finished successfully. Safe to fetch analytics.
{
"creator_id": "…",
"job_id": "…"
}creator.failed
Creator processing failed.
{
"creator_id": "…",
"job_id": "…",
"error_message": "…"
}analysis.completed
A sync clip analyze request finished (async analyze does not emit this yet).
{
"clip_id": "…",
"collection_id": "…",
"workspace_id": "…",
"external_user_id": null
}credits.depleted
The account ran out of ClipSonar credits and processing was paused.
{
"account_id": "…"
}insights.ready
Reserved for future insight-refresh notifications. Not emitted yet.
{ }Verify signatures
Always verify against the raw request body before parsing JSON. Compare with a timing-safe equality check.
const crypto = require('crypto');
function verifyClipSonarSignature(rawBody, signatureHeader, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
);
}

