Webhooks
Webhooks push events to your own HTTPS endpoint instead of you polling the API. APIXX signs every delivery, retries with exponential backoff, and keeps a 30-day delivery log you can replay from.
Setting up an endpoint
- Go to Settings → Webhooks and click Add endpoint.
- Provide an HTTPS URL. Plain HTTP is rejected.
- Pick the events to subscribe to.
- Copy the generated signing secret — it's shown once.
- Click Send test event to verify your endpoint returns 2xx within 10 seconds.
Events
| Event | When | Payload contains |
|---|---|---|
| run.started | A flow run begins. | flow id, run id, trigger. |
| run.succeeded | Run completes with zero record errors. | records processed, duration. |
| run.partial | Run completes with some failures. | success/fail counts, top errors. |
| run.failed | Run aborts before completing. | error trace, stage. |
| connector.degraded | A connector starts returning auth/quota errors. | connector id, error summary. |
| connector.recovered | A degraded connector returns to active. | connector id, downtime duration. |
| flow.paused | A flow is paused. | flow id, actor. |
| flow.resumed | A flow is resumed. | flow id, actor. |
Payload shape
POST /your-endpoint
Content-Type: application/json
X-Apixx-Event: run.failed
X-Apixx-Delivery: del_4nQ2k
X-Apixx-Signature: t=1781119222,v1=8f4a2c...
{
"event": "run.failed",
"delivery_id": "del_4nQ2k",
"created_at": "2026-06-12T18:21:04Z",
"customer_id": "cus_82h",
"data": {
"run_id": "run_91A",
"flow_id": "flw_8sJk2",
"stage": "write",
"error": { "code": "destination_rejected", "message": "Missing required field 'tax_code'." }
}
}Signature verification
Compute HMAC-SHA256(signing_secret, timestamp + "." + raw_body) and compare with a timing-safe equality check. Reject deliveries with a timestamp older than 5 minutes (replay protection).
import { createHmac, timingSafeEqual } from "crypto";
function verify(req, secret) {
const header = req.headers["x-apixx-signature"];
const [tPart, sigPart] = header.split(",");
const timestamp = tPart.slice(2);
const signature = sigPart.slice(3);
// Replay protection
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected = createHmac("sha256", secret)
.update(timestamp + "." + req.rawBody)
.digest("hex");
return timingSafeEqual(Buffer.from(signature, "hex"), Buffer.from(expected, "hex"));
}Retries & ordering
- Non-2xx (or no response in 10s) triggers retries: 30s, 2m, 10m, 1h, 6h, 24h. We give up after 24h.
- Events are delivered at-least-once. Dedupe with
X-Apixx-Delivery. - Ordering is best-effort per event type per object. If strict ordering matters, sort by
created_aton receive. - Return 2xx as soon as the payload is persisted; do heavy work asynchronously.
Delivery logs
Every attempt is logged for 30 days under Settings → Webhooks → Deliveries: status, latency, request/response headers, body. Failed deliveries have a one-click Replay button that re-sends with a fresh signature.
Local testing
Use any tunnel tool (ngrok, Cloudflare Tunnel) to expose your dev server. Register the tunnel URL as a webhook endpoint, then click Send test event. You can also call POST /v1/webhooks/:id/test from the API.
