Skip to content
Logo

Customer events

The status_changed events fire when a customer's verification status changes to a different KyStatus. Backwards moves fire too — a customer released from a paused hold back into under_review is announced. Verification also runs in stages, and the events fire once more when a later stage completes without moving the rolled-up status: the payload's expanded flag distinguishes that case.

Both events carry an updated_at: when the customer's verification record last changed. The status each event reports is rolled up across the verification checks in flight rather than stored in one column, so updated_at is the most recent of those checks' own updates — the write a verdict actually moves. It is absent for an entity with no checks on record yet.

customer.kyc.status_changed

Fired when an individual customer's KYC verification status changes.

{
  "event_type": "customer.kyc.status_changed",
  "created_at": "2026-08-27T08:05:05.883Z",
  "data": {
    "customer_id": "2f10…",
    "status": "approved",
    "expanded": true,
    "updated_at": "2026-08-27T08:05:05.740Z",
    "kyc_profile": {
      "identity": { "first_name": "Ada", "last_name": "Lovelace", "...": "…" },
      "addresses": { "residential": { "...": "…" } },
      "contact": { "email": "ada@example.com", "...": "…" },
      "employment": { "...": "…" },
      "risk": { "...": "…" },
      "volumes": { "...": "…" },
      "jurisdictions": { "...": "…" },
      "attestations": { "...": "…" },
      "documents": { "...": "…" },
      "supplemental": [{ "...": "…" }]
    }
  }
}
FieldTypeNotes
customer_idUUIDThe customer whose KYC status changed.
updated_atstringWhen the verification record last changed, RFC-3339 UTC with millisecond precision. Optional. Absent for a customer with no verification checks on record, and on events delivered before the field existed.
statusKyStatusNew aggregate status. One of draft, submitted, under_review, approved, rejected, terminally_rejected, paused, unknown.
expandedbooleanWhether this update completed an additional verification approval. See the expanded flag.
kyc_profileKycProfileFull saved profile at event time. Optional in the schema. See Backfill caveat.

customer.kyb.status_changed

Fired when a business customer's KYB verification status changes.

{
  "event_type": "customer.kyb.status_changed",
  "created_at": "2026-08-27T08:05:05.883Z",
  "data": {
    "customer_id": "8e3b…",
    "status": "approved",
    "expanded": true,
    "updated_at": "2026-08-27T08:05:05.740Z",
    "kyb_profile": {
      "business": { "legal_name": "Acme Industries Ltd", "...": "…" },
      "addresses": { "registered": { "...": "…" } },
      "contact": { "...": "…" },
      "operations": { "...": "…" },
      "volumes": { "...": "…" },
      "counterparties": { "...": "…" },
      "attestations": { "...": "…" },
      "associated_persons": [{ "...": "…" }],
      "supplemental": [{ "...": "…" }],
      "documents": [{ "...": "…" }]
    }
  }
}
FieldTypeNotes
customer_idUUIDThe customer whose KYB status changed.
updated_atstringWhen the verification record last changed, RFC-3339 UTC with millisecond precision. Optional. Absent for an entity with no verification checks on record, and on events delivered before the field existed.
statusKyStatusNew aggregate status. Same enum as KYC.
expandedbooleanWhether this update completed an additional verification approval. See the expanded flag.
kyb_profileKybProfileFull saved profile at event time. Optional in the schema. See Backfill caveat.

customer.virtual_account_approval.changed

Fired when a customer's approval for a virtual account in a currency changes, once the customer's verification is approved. Some currencies have a virtual-account review of their own, on top of the customer's verification, so the two can clear at different times. This event waits for both: an account approval that clears before verification is sent together with the verification's approved event. status: "approved" here means the account can be requested now.

{
  "event_type": "customer.virtual_account_approval.changed",
  "created_at": "2026-10-20T21:29:03.023Z",
  "data": {
    "customer_id": "2f10…",
    "currency": "USD",
    "status": "approved",
    "banks": [
      "JPMORGAN_BANK",
      "PORTAGE_BANK"
    ],
    "updated_at": "2026-10-20T21:28:59.000Z"
  }
}
FieldTypeNotes
customer_idUUIDThe customer whose approval changed.
currencystringThe currency of the virtual account, e.g. USD.
statusstringWhere the approval stands, in the same terms as GET /customers/:id/virtual-account-approvals: approved, pending, action_required, rejected, or not_started.
banksstring[]The banks status applies to, as GET /customers/:id/virtual-account-banks spells them. Absent when status applies to every bank the customer can be offered.
updated_atstringWhen the change was reported, RFC-3339 UTC with millisecond precision. Optional.

The event fires once per change while the customer is verified; a repeat of the same approval is silent. A create made within a minute of the event can still be refused with VirtualAccountNotApproved while the previous answer expires, so retry it.

The expanded flag

Verification runs in stages, and later stages may conclude after the rolled-up status has already settled. expanded is true whenever the update that fired the event completed at least one additional verification approval — independent of what status did:

  • A first approval that also moves status to approved carries expanded: true.
  • A status change that completed no new approval — a revocation, a rejection — carries expanded: false.
  • A submission returned by Seismic's review fires with status: "rejected" and the review's reason on the customer's rejection_reason; entering submitted does not fire.
  • A follow-on approval that changes nothing about status still fires the event, with the unchanged status and expanded: true.

Treat expanded: true with an unchanged status as "an additional approval completed": the payload does not say which, so on receipt re-read the approvals endpoints to pick up anything newly available.

Events delivered before the flag existed omit it; freshly-emitted events always carry it.

Backfill caveat

The embedded kyc_profile / kyb_profile field is optional in the published JSON Schema. Freshly-emitted events always include it. Replays of older deliveries may not. Fall back to GET /v0/customers/:id in that case.