Platform
Webhooks
Signed delivery, five retries, seven days of replay.
Everything aux0 learns reaches you here. Polling works, but it is slower, costs API calls, and misses the events that have no object to poll for.
Subscribe
curl https://api.aux0.com/v1/webhooks \
-H "Authorization: Bearer $AUX0_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.example.com/hooks/aux0",
"events": ["message.received", "account.needs_attention"]
}'The response includes a signing secret, shown once.
Verify the signature
Every request carries aux0-signature, an HMAC-SHA256 of
<timestamp>.<raw body>, and aux0-timestamp.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(raw: string, signature: string, timestamp: string) {
// Reject anything older than five minutes, so a captured request cannot be
// replayed against you later.
const age = Math.abs(Date.now() / 1000 - Number(timestamp));
if (!Number.isFinite(age) || age > 300) return false;
const expected = createHmac("sha256", process.env.AUX0_WEBHOOK_SECRET!)
.update(`${timestamp}.${raw}`)
.digest("hex");
// A plain === leaks the comparison's timing.
const a = Buffer.from(expected);
const b = Buffer.from(signature);
return a.length === b.length && timingSafeEqual(a, b);
}Verify against the raw body. Parsing and re-serialising changes the bytes and the signature will not match.
The events
| Event | Fires when |
|---|---|
message.received | An inbound message arrives. |
message.sent | An outbound message leaves aux0. |
message.status_changed | Delivered, read or failed. |
chat.created | A conversation appears that aux0 has not seen. |
email.received / email.sent | The mail equivalents. |
email.opened | A tracked message was opened. |
account.connected | A user finished hosted auth. |
account.sync_completed | The first backfill finished. |
account.needs_attention | The provider wants the end user. |
account.disconnected | aux0 stopped retrying the session. |
invite.accepted | A connection request was accepted. |
post.comment_received | Someone commented on a post the account published. |
Delivery
- Timeout 10 seconds. Return a 2xx quickly and do the work after; a slow endpoint eventually looks like a failing one.
- Retries five, over about 30 minutes, with exponential backoff.
- Order is not guaranteed. Use
created_atand treatidas idempotent — a retry can arrive after you already processed the first attempt. - Replay failed deliveries are held for 7 days and can be replayed from the dashboard or the API once your endpoint recovers.
Testing locally
Point a sandbox webhook at a tunnel:
curl https://api.aux0.com/v1/webhooks \
-H "Authorization: Bearer $AUX0_API_KEY" \
-d '{ "url": "https://your-tunnel.ngrok.app/aux0", "events": ["message.received"] }'The dashboard's delivery list shows the exact payload sent and the response received, which is usually faster than adding logging to find out why something did not arrive.