Skip to main content
Register an HTTPS endpoint with POST /v1/webhooks. Apocor POSTs a signed JSON envelope for each matching domain event. Events are also available via GET /v1/events?starting_after= (same ids as webhooks) for reconciliation.
Example event

Event catalog

Full machine-readable list: GET /v1/webhooks/event-types.
Events fire only on actual state changes. Freezing an already-frozen card returns 200 but emits no second card.frozen. Likewise applicant.status_changed fires only when the tenant-visible status changes — internal verification stages that don’t move the collapsed status stay silent, and concurrent processing paths are deduped so each transition is emitted once.

Verifying signatures

Header: X-Webhook-Signature: t=<unix_ts>,v1=<hex>
Signed payload: {timestamp}.{raw_body} with HMAC-SHA256 using your endpoint secret.
During secret rotation (POST /v1/webhooks/{id}/rotate-secret), verify against the new secret or the previous secret until previous_secret_expires_at (48h overlap). Also sent: X-Webhook-Id (immutable event id — dedupe on this), X-Webhook-Event.

Latency

First delivery attempt is typically 1–2 seconds after Apocor persists the event (target under 5 seconds). This is after our commit, not a synchronous hook on the card-network authorization path. We retry up to 6 times with backoff, then dead-letter. Return 2xx immediately and process asynchronously.

Managing subscriptions

Redelivered events carry the same event id — receivers that dedupe on X-Webhook-Id handle them for free.

Reconcile missed events

  1. Primary: GET /v1/events?starting_after={last_event_id}&limit=100
  2. Resource GETs: KYC status, card, issuance, transactions, funding balances
  3. Delivery log: GET /v1/webhooks/{id}/deliveries + redeliver

Best practices

Respond fast

Return 2xx immediately and process asynchronously. Slow handlers risk timeouts and retries.

Be idempotent

Deliveries may repeat. De-duplicate on the event id.

Verify every time

Check the signature on every request, not just the first.

Use HTTPS

Only register TLS endpoints so payloads stay encrypted in transit.

Issuance notes

  • POST /v1/cards requires Idempotency-Key (72h window). Optional reference_id — unique per program + environment; query with GET /v1/cards?reference_id=.
  • Async: 202 + issuance_id; poll GET /v1/cards/issuances/{id}.
  • In-flight same key → 409 with issuance_id.
  • POST /v1/cards/{id}/fund, fund-from-wallet, and defund also require Idempotency-Key.