APIXX.flow logo
Back to app
Developer reference

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

  1. Go to Settings → Webhooks and click Add endpoint.
  2. Provide an HTTPS URL. Plain HTTP is rejected.
  3. Pick the events to subscribe to.
  4. Copy the generated signing secret — it's shown once.
  5. Click Send test event to verify your endpoint returns 2xx within 10 seconds.

Events

EventWhenPayload contains
run.startedA flow run begins.flow id, run id, trigger.
run.succeededRun completes with zero record errors.records processed, duration.
run.partialRun completes with some failures.success/fail counts, top errors.
run.failedRun aborts before completing.error trace, stage.
connector.degradedA connector starts returning auth/quota errors.connector id, error summary.
connector.recoveredA degraded connector returns to active.connector id, downtime duration.
flow.pausedA flow is paused.flow id, actor.
flow.resumedA 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"));
}
Use the raw body
Compute the signature against the exact bytes you received — not against re-serialized JSON. Frameworks that auto-parse can change key ordering or whitespace and break the HMAC.

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_at on 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.