Webhooks
Ante POSTs JSON to your HTTPS URL when a group's state changes. Verify Ante-Signature on the raw body before you mark an order paid or ship goods.
Copy this page as a setup prompt for your coding assistant.
Two ways to receive events
| Source | Secret for verification | Typical use |
|---|---|---|
| Dashboard endpoint | whsec_… (shown once when you register the URL) | One stable URL, event filters, delivery log in portal |
| Per-session webhook_url | Merchant signing secret (ante_sign_…, same as cart signing) | Different URL per order; set on session create from SDK or REST |
Register dashboard URLs at Merchants → Webhooks. Pass webhook_url on session create for per-order delivery. Both can fire for the same event if URLs overlap.
Envelope
Every delivery uses this shape. Parse type and act on data.
{
"id": "evt_1719234567890",
"type": "group.funded",
"created_at": "2025-06-24T14:30:00.000Z",
"data": { }
}Event types and payloads
group.created
Session exists; organizer opened the group. Useful for analytics or holding inventory lightly.
{
"session_id": "j57…",
"group_id": "j57…",
"order_ref": "ORD-1042",
"expiry_at": "2025-06-25T14:30:00.000Z"
}group.funded
Every share is paid. Ante started merchant payout. Use this to fulfill. transfer_id is the Stripe transfer when available (none in sandbox). When checkout currency differs from your preferred payout currency, FX fields are included — see Currencies & payouts → Important limitations and webhook fields.
{
"session_id": "j57…",
"group_id": "j57…",
"transfer_id": "tr_…",
"total": 12000,
"merchant_fee": 241,
"order_ref": "ORD-1042",
"checkout_currency": "eur",
"payout_currency_preference": "usd",
"fx_fee_cents": 196,
"merchant_transfer_cents": 9603
}group.expired
Funding window closed with balance outstanding. Paid shares are refunded.
{
"session_id": "j57…",
"group_id": "j57…",
"order_ref": "ORD-1042",
"refunded": true,
"reason": "expired"
}group.cancelled
Merchant cancelled via API or dashboard flow. Refunds when shares were already paid.
{
"session_id": "j57…",
"group_id": "j57…",
"refunded": true,
"cancelled_by": "merchant"
}Verify Ante-Signature
Header example: Ante-Signature: t=1719234567,v1=abc123…. t is Unix seconds. v1 is HMAC-SHA256 hex of {t}.{rawRequestBody} using your endpoint secret. Reject if timestamp is more than 300 seconds from your server clock.
import { verifyWebhookSignature } from "@splitante/sdk/signing";
export async function POST(req: Request) {
const rawBody = await req.text();
const header = req.headers.get("ante-signature") ?? "";
const secret = process.env.ANTE_WEBHOOK_SECRET!; // whsec_… or signing secret
if (!verifyWebhookSignature(rawBody, secret, header)) {
return new Response("Invalid signature", { status: 401 });
}
const event = JSON.parse(rawBody);
if (event.type === "group.funded") {
await fulfillOrder(event.data.order_ref, event.data.session_id);
}
return Response.json({ received: true });
}Handler timing
Return 2xx within 30 seconds. Queue heavy work after the response. Non-2xx and timeouts trigger retries.
Retries
Up to 12 attempts. Delays after failure (approximate):
| Attempt | Wait before retry |
|---|---|
| 1 | immediate |
| 2 | 30s |
| 3 | 1m |
| 4 | 2m |
| 5 | 5m |
| 6 | 10m |
| 7 | 30m |
| 8 | 1h |
| 9 | 2h |
| 10 | 3h |
| 11 | 4h |
| 12 | 5h |
Status per delivery: Webhooks → Recent deliveries.
Test
Use "Send test" on a registered endpoint, or complete a sandbox checkout and pay every share. Local dev needs a public HTTPS URL (tunnel). Ante does not call localhost directly.