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": [{ "...": "…" }]
}
}
}| Field | Type | Notes |
|---|---|---|
customer_id | UUID | The customer whose KYC status changed. |
updated_at | string | When 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. |
status | KyStatus | New aggregate status. One of draft, submitted, under_review, approved, rejected, terminally_rejected, paused, unknown. |
expanded | boolean | Whether this update completed an additional verification approval. See the expanded flag. |
kyc_profile | KycProfile | Full 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": [{ "...": "…" }]
}
}
}| Field | Type | Notes |
|---|---|---|
customer_id | UUID | The customer whose KYB status changed. |
updated_at | string | When 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. |
status | KyStatus | New aggregate status. Same enum as KYC. |
expanded | boolean | Whether this update completed an additional verification approval. See the expanded flag. |
kyb_profile | KybProfile | Full 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"
}
}| Field | Type | Notes |
|---|---|---|
customer_id | UUID | The customer whose approval changed. |
currency | string | The currency of the virtual account, e.g. USD. |
status | string | Where the approval stands, in the same terms as GET /customers/:id/virtual-account-approvals: approved, pending, action_required, rejected, or not_started. |
banks | string[] | 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_at | string | When 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
statustoapprovedcarriesexpanded: 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'srejection_reason; enteringsubmitteddoes not fire. - A follow-on approval that changes nothing about
statusstill fires the event, with the unchanged status andexpanded: 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.