Skip to main content

Inbound — Core API (target)

Provider webhooks are received by the Apocor Core API. Register these HTTPS URLs in each vendor dashboard (use your environment host).
ProviderPathSandboxProduction
SumsubPOST /v1/webhooks/sumsubhttps://sandbox.apocor.ai/v1/webhooks/sumsubhttps://api.apocor.com/v1/webhooks/sumsub
InterlacePOST /v1/webhooks/interlacehttps://sandbox.apocor.ai/v1/webhooks/interlacehttps://api.apocor.com/v1/webhooks/interlace
DynamicPOST /v1/webhooks/dynamichttps://sandbox.apocor.ai/v1/webhooks/dynamichttps://api.apocor.com/v1/webhooks/dynamic
Env varPurpose
APOCOR_PUBLIC_API_URLPublic Core API base (drives sumsubWebhookUrl when mode is apocor)
SUMSUB_WEBHOOK_MODE=apocorRoute Sumsub callbacks to Core API (required for cutover)
SUMSUB_WEBHOOK_SECRETHMAC verification for Sumsub
INTERLACE_WEBHOOK_SECRETSignature verification for Interlace
DYNAMIC_WEBHOOK_SECRETHMAC verification for Dynamic (x-dynamic-signature-256)
GET /v1/kyc/config returns sumsubWebhookUrl and sumsubWebhookMode for your environment — use that URL when registering Sumsub. After hosted Sumsub verification, you can still call POST /v1/applicants/{id}/submit to sync tenant KYC and trigger issuer handoff. Poll GET /v1/applicants/{id}/kyc-status for issuer progress — see KYC integration. Cutover steps (dashboards + Railway env): see scripts/aws/WEBHOOK_CUTOVER.md in the monorepo.

Legacy — seismic-cards (migration only)

Older deployments used the seismic-cards Railway service with SUMSUB_WEBHOOK_MODE=seismic and path /webhooks/sumsub (no /v1). That path is legacy — do not register new Sumsub webhooks there. Keep seismic only until the Sumsub dashboard points at Core API, then set SUMSUB_WEBHOOK_MODE=apocor.
Legacy (do not use for new setup)
URLhttps://api-production-XXXX.up.railway.app/webhooks/sumsub
ModeSUMSUB_WEBHOOK_MODE=seismic + SEISMIC_SUMSUB_WEBHOOK_URL

Outbound — Apocor → your app

Apocor will send outbound webhooks to your endpoint so you can react to events without polling — an applicant is approved, a card changes state, or a credit purchase settles.
Outbound delivery is not yet available on all endpoints (POST /v1/webhooks returns not implemented). The sections below describe the planned contract.

Delivering events

You register an HTTPS endpoint and the events you care about. Apocor POSTs a JSON body to that URL for each matching event.
Example event
{
  "id": "evt_abc123",
  "type": "card.activated",
  "createdAt": "2026-07-07T10:15:00.000Z",
  "data": { "id": "card_abc123", "status": "ACTIVE" }
}

Verifying signatures

Each delivery is signed with the secret from your webhook subscription. Compute an HMAC-SHA256 over the raw request body and compare it, in constant time, to the signature header.
import crypto from "node:crypto";

function verify(rawBody: string, signature: string, secret: string): boolean {
  const digest = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(digest);
  const b = Buffer.from(signature);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Always verify against the raw request body before parsing JSON. Reject any request whose signature does not match.

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.