Skip to content

API Reference

Webhooks

A POST notification to your server when a generation finishes — body format, HMAC-SHA256 signature check, response deadline and the redelivery schedule.

Pass a webhook_url when you submit a generation, and Clipia sends a POST to that address when the job finishes. You don't need to poll the status. Every delivery is signed with HMAC-SHA256 using your key's secret, and a failed delivery is retried for about a day.

URL requirements

  • https:// only. Addresses on internal or private networks are rejected at submit time with 400 webhook_url_invalid.
  • Redirects aren't followed: a 3xx response counts as a failed delivery.

Body

Success:

{
  "request_id": "764cabcf-b745-4b3e-ae38-1200304cf45b",
  "status": "OK",
  "payload": {
    "model": "nano-banana-2",
    "output": { "images": [{ "url": "https://media.clipia.ai/....webp" }] },
    "cost": 12
  }
}

Generation failure:

{
  "request_id": "764cabcf-b745-4b3e-ae38-1200304cf45b",
  "status": "ERROR",
  "error": {
    "code": "generation_failed",
    "message": "Generation failed. Please retry or contact support."
  }
}

output depends on the model type: images: [{ url }], video: { url } or audio: { url, format? } together with audios: [{ url, format? }] (every track variant, the first one equals audio). error.code comes from the generation error dictionary: generation_failed, content_moderated, model_unavailable and others; treat an unknown code as generation_failed.

The webhook body is shorter than the REST response

Webhooks carry no original_url or thumbnail_url, and images come with a single link. Fetch the full result with GET /v1/requests/:id.

Prop

Type

Headers

Content-Type: application/json
X-Clipia-Webhook-Id: 1f2e3d4c-5b6a-7890-abcd-ef0123456789
X-Clipia-Timestamp: 1760011200
X-Clipia-Signature: t=1760011200,v1=5257a869e7...
HeaderValue
X-Clipia-Webhook-Iddelivery ID, the same across all retries
X-Clipia-TimestampUnix time of this attempt, in seconds
X-Clipia-Signaturet=<timestamp>,v1=<hex HMAC-SHA256>

Signing secret

Each API key has its own secret, used to sign webhooks for jobs submitted with that key. The secret is shown once, when you create the key in the Developer Console. The console has no delivery history or manual resend. If you lose the secret, create a new key and switch your integration to it — see Managing keys.

Verifying the signature

The signature is HMAC_SHA256(secret, "{timestamp}.{raw_body}"). Verify it against the raw request body before parsing JSON, compare in constant time, and reject deliveries older than 5 minutes. The easiest way is the ready-made SDK function.

import { verifyWebhookSignature } from 'clipia-ai/webhook';

// rawBody is the original body bytes, not JSON.stringify(req.body)
const ok = verifyWebhookSignature({
  secret: process.env.CLIPIA_WEBHOOK_SECRET!,
  headers: req.headers,
  body: rawBody,
  toleranceSeconds: 300,
});
if (!ok) return res.status(401).end();

Both SDK functions return true or false and never throw on malformed headers.

Delivery and retries

  • Respond with 2xx within 10 seconds. Do heavy processing after you respond.
  • A non-2xx response, a 3xx, or a timeout counts as a failure. Delivery is attempted up to 15 times in total.
  • The pause between attempts doubles, starting at 30 seconds, capped at 4 hours: 30 s, 1, 2, 4, 8, 16, 32 min, 1 h 04 min, 2 h 08 min, then 4 hours each — about 24 hours 15 minutes in total from the first attempt. Deliveries are dispatched every 30 seconds, so the actual delay can be slightly longer.
  • After the last failed attempt the delivery is marked as failed and is not retried again; it cannot be requested anew. If your handler was down for longer, fetch the result with GET /v1/requests/:id — it is stored independently of the webhook.

Handle deliveries idempotently

The same delivery can arrive more than once, for example if your response got lost. Deduplicate by X-Clipia-Webhook-Id or request_id before triggering side effects.

In the sandbox, webhooks are delivered and signed the same way — a convenient way to test your handler. A test key gets at most one delivery per minute: the rest within that minute are not created, and a failed delivery stops after three attempts.