Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.antonpayments.com/llms.txt

Use this file to discover all available pages before exploring further.

Webhooks are how Anton tells your system that something happened without you having to ask. A payout settles, a beneficiary is blocked, an RFI is raised — Anton signs a JSON event and POSTs it to an HTTPS URL you control. This guide covers the integrator’s end-to-end: how to subscribe, how to verify signatures, how to handle retries, and what patterns your receiver should follow.

When to use webhooks (vs polling)

Always use webhooks in production. Polling has three problems:
  • Wastes rate-limit budget — GET /v1/payouts/{id} in a loop quickly hits the 1,000 req/min per-merchant ceiling.
  • Introduces latency — you learn about state changes on your polling interval, not when they happen.
  • Misses intermediate transitions — by the time you poll, a payout may have already moved through two states.
Polling is fine during development when you don’t yet have a public HTTPS endpoint. For production, subscribe.

Creating a subscription

curl https://api.antonpayments.dev/v1/webhooks \
  -X POST \
  -H "Authorization: DPoP $ANTON_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.example.com/webhooks/anton",
    "events": [
      "payout.completed",
      "payout.failed",
      "payout.returned",
      "payout.screening_failed",
      "beneficiary.blocked",
      "rfi.created"
    ]
  }'
The URL must be:
  • HTTPShttp:// is rejected in all non-development environments.
  • Publicly reachable — private IP ranges, loopback, and cloud metadata endpoints (e.g. 169.254.169.254) are rejected server-side.
The response includes the subscription id (wbh_...) and a one-time secret (whsec_...). Store the secret in your secrets manager immediately — Anton doesn’t retain the plaintext, and you cannot retrieve it later without calling GET /v1/webhooks/{id}/secret (which you can, but rotating is cleaner). Use ["*"] as the events array to subscribe to everything.

Signing and verification

Every delivery carries HMAC-SHA256 headers:
  • X-Webhook-Signature: v1={hex-hmac}
  • X-Webhook-Timestamp: {unix-seconds}
  • X-Webhook-ID: {event-id} — use for deduplication
  • X-Webhook-Event: {event-type}
  • User-Agent: AntonPayments-Webhook/1.0
The signed string is {timestamp}.{raw-body}. Verify every delivery in constant time. See Webhook Signing for copy-paste verification code in bash, JavaScript, PHP, and Go. Treat unverified deliveries as untrusted HTTP requests — do not act on the payload until the signature checks out.
Parse the raw request body, not parsed-and-reserialized JSON. Re-encoding changes byte ordering and breaks verification.

Delivery semantics

  • At-least-once. Subscribers may occasionally receive the same event twice. Deduplicate on the envelope id.
  • Ordering — events for the same resource dispatch in the order they occur, but network retries can re-order arrivals at your endpoint. Don’t assume order; reconcile state from the payload.
  • Retries — failed deliveries retry with exponential backoff: 30s, 2m, 8m, 32m, hourly. Up to 5 total attempts. After 5 failures, the delivery is abandoned.
  • Timeout — Anton waits up to 30 seconds for your 2xx response. Return 2xx fast and do heavy work asynchronously (enqueue, then respond).
  • Redirects — not followed. Your URL must respond directly.
A delivery is successful when your endpoint returns any 2xx status code. Non-2xx responses (including 3xx) count as failure and trigger retries.

The events you probably want

Core payout lifecycle:
  • payout.completed — funds delivered
  • payout.failed — rail rejected or failed settlement
  • payout.returned — funds returned after send
  • payout.screening_failed — sanctions or compliance block
  • payout.velocity_blocked — velocity rule rejected
Beneficiary lifecycle:
  • beneficiary.created
  • beneficiary.updated — edit, PII update, archive, or restore
  • beneficiary.blocked — compliance action
Compliance workflow:
  • rfi.created — Anton raised a Request for Information
  • screening.hit — payout held pending screening review
FX:
  • fx.exchange.completed, fx.exchange.failed
Funding:
  • funding.credit — deposit landed in your balance
The full catalog (27 event types) with payload schemas is at Webhook Events.

Receiver patterns

A production-ready webhook receiver does four things in order:
1

Enqueue fast

Read the raw body, enqueue it for async processing, return 200 immediately. Don’t block on database writes or downstream API calls inside the request handler — Anton’s 30-second timeout is generous but chains of dependent work can exceed it.
2

Verify the signature

Before the enqueued worker trusts the payload, verify the signature using the stored secret. Reject anything older than 5 minutes (replay protection).
3

Deduplicate

Check the envelope id against a recent-events store (Redis SET with TTL works). Skip if already seen. At-least-once delivery means this IS going to happen.
4

Apply idempotently

Design your event handlers so applying the same event twice converges on the same state. Use the resource’s status as the source of truth — payout.completed twice should move a payout to completed once.

Debugging delivery failures

GET /v1/webhooks/events/{id}/deliveries returns every delivery attempt Anton made for a given event — the exact request headers sent, your response status, response body (truncated), transport errors, duration, and retry schedule. When a delivery is failing, this is where you look:
curl "https://api.antonpayments.dev/v1/webhooks/events/$EVENT_ID/deliveries" \
  -H "Authorization: DPoP $ANTON_ACCESS_TOKEN"
Common failure modes:
  • Signature mismatch (400 from your endpoint) — you’re verifying against a parsed body instead of the raw bytes, or the secret rotated and you didn’t update.
  • Connection timeout — your endpoint took longer than 30s to respond. Move work off the request path.
  • 5xx from your endpoint — application error; look at your own logs.
  • Certificate errors — your HTTPS cert is expired, self-signed, or mismatched to the hostname.

Testing without waiting for real events

Fire a synthetic delivery via POST /v1/webhooks/{id}/test:
curl https://api.antonpayments.dev/v1/webhooks/$WBH_ID/test \
  -X POST \
  -H "Authorization: DPoP $ANTON_ACCESS_TOKEN"
Anton sends a test event to your subscription. Use it to validate connectivity, signature verification, and response handling before depending on real events in sandbox tests.

Secret rotation

When a secret might be compromised — or on a schedule — rotate it:
curl https://api.antonpayments.dev/v1/webhooks/$WBH_ID/secret/rotate \
  -X POST \
  -H "Authorization: DPoP $ANTON_ACCESS_TOKEN"
The response contains the new secret — again, shown once. Rotation has no overlap window — the old secret is invalidated immediately. Plan rotations for low-traffic periods, and update your receiver’s secret in lockstep.

Deactivation vs deletion

  • Deactivate (POST /v1/webhooks/{id}/deactivate) — stop delivering events. Subscription stays as a record; reactivation may be a supported future path.
  • Delete (DELETE /v1/webhooks/{id}) — permanent. Event history remains for audit, but no new deliveries.
Prefer deactivate during incidents so you can resume later.

Next steps

Webhook event catalog

Every event type and its payload schema.

Webhook signing

Copy-paste HMAC verification in 4 languages.