Docs/Platform Features

Webhooks

Event types, payload shape, signature verification, and delivery semantics.

Webhooks let Tarqa tell your server when something happens, such as a failed API call or a new key, by sending a POST to an HTTPS URL you choose.

Available on the Pro, Team and Enterprise plans. Add an endpoint in Developer → Webhooks or with POST /v1/webhooks. The signing secret is shown once, when you create it.

Set one up

  1. 1
    Create the endpoint
    In the dashboard (or via the API), enter your URL and pick the events you want. Copy the signing secret.
  2. 2
    Verify every delivery
    Check the signature with your secret (code below) and reject anything that doesn't match.
  3. 3
    Reply fast
    Return any 2xx within 10 seconds and do the real work in the background.
  4. 4
    Send a test
    Click Test (or POST /v1/webhooks/:id/test) to receive a webhook.test event.

Events

EventFires whendata fields
api.call.succeededAn API request finishes with 2xxendpoint, method, status_code, model, timestamp
api.call.failedAn API request finishes with non-2xxendpoint, method, status_code, model, timestamp
key.createdA new API key is createdkey_id, name, key_prefix, created_at
team.member.invitedSomeone is invited to your teamemail, role, team_id, invited_at
webhook.testYou send a test deliverymessage, webhook_id, user_id

What we send

Every delivery is a POST with this body:

JSON
{
  "id": "d3f1c8a2-5b6e-4c11-9a0f-7e2d4b8c1a90",
  "event": "api.call.succeeded",
  "data": { "endpoint": "/v1/chat/completions", "method": "POST", "status_code": 200, "model": "claude-opus-4-6", "timestamp": "2026-09-03T10:30:00.000Z" },
  "webhook_id": "b1a2c3d4-...",
  "timestamp": "2026-09-03T10:30:00.123Z"
}
FieldMeaning
idUnique per delivery and the same across retries of that delivery. Dedupe on this.
webhook_idYour endpoint's ID. The same for every delivery to this URL, so it is not a dedupe key.
timestampWhen the delivery was created (ISO 8601).

And these headers:

HeaderValue
X-Webhook-SignatureHMAC-SHA256 of the raw body, hex, no prefix
X-Webhook-EventThe event name
X-Webhook-IdSame as id: the dedupe key
X-Webhook-TimestampSame as timestamp
User-AgentTarqaAI-Webhook/1.0

Verify the signature

Compute HMAC-SHA256 over the exact raw body bytes with your secret, and compare it to X-Webhook-Signature in constant time. Also reject deliveries older than about 5 minutes.

import crypto from 'crypto';
// Needs the raw body: express.raw({ type: 'application/json' })

function verify(req, secret) {
  const expected = crypto.createHmac('sha256', secret).update(req.body).digest('hex');
  const got = req.get('X-Webhook-Signature') || '';
  return expected.length === got.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(got));
}

app.post('/tarqa-webhook', express.raw({ type: 'application/json' }), (req, res) => {
  if (!verify(req, process.env.TARQA_WEBHOOK_SECRET)) return res.sendStatus(401);

  const ts = Date.parse(req.get('X-Webhook-Timestamp'));
  if (Math.abs(Date.now() - ts) > 5 * 60 * 1000) return res.sendStatus(401); // too old

  const event = JSON.parse(req.body.toString());
  if (!seen(event.id)) enqueue(event); // dedupe, then process in the background
  res.sendStatus(200);                 // reply fast
});
Rotating the secret

POST /v1/webhooks/:id/rotate creates a new secret and returns it once. The old one stops working immediately, so deploy the new secret first.

How delivery works

RuleDetails
At least onceA delivery can arrive more than once (e.g. you processed it but timed out). Dedupe on X-Webhook-Id.
RetriesUp to 4 attempts: the first send, then retries after 1s, 5s and 15s. Retries survive a restart on our side.
TimeoutEach attempt waits 10 seconds. Slower counts as failed and is retried, so reply first and work later.
SuccessAny 2xx. Your response body is saved in the delivery log but not interpreted.
OrderNot guaranteed. A retried older event can arrive after a newer one; use timestamp if order matters.
Auto-disableAfter 15 failed deliveries in a row the endpoint is switched off. Re-enable it in the dashboard once it's fixed.
Replay protectionUp to you: check X-Webhook-Timestamp against a window (5 minutes is reasonable). We don't reject replays.

Debug a failing endpoint

GET /v1/webhooks/:id/deliveries lists recent attempts with status code, a response snippet, attempt count and error, so you can fix it before it auto-disables.

FAQ

I lost my signing secret.
Rotate it with POST /v1/webhooks/:id/rotate (or in the dashboard) and deploy the new one.
Why did I get the same event twice?
Delivery is at-least-once. Store id values you've handled and skip repeats.
My endpoint stopped receiving events.
It was probably auto-disabled after 15 failures in a row. Check the delivery log, fix it, then re-enable it.