Skip to main content
Learn which events you can subscribe to, how to use subscription patterns, and what every webhook payload looks like.

Available Event Types

Event TypeDescription
kyc.status.changedKYC verification status has changed
card.activatedA card has been activated
transaction.clearedA transaction has cleared
Additional event types will be added as the platform grows. Contact your account team to discuss events relevant to your integration.

Subscription Patterns

When configuring your webhook, you can subscribe using three pattern styles:
PatternDescriptionExample
Exact MatchSubscribe to one specific eventkyc.status.changed
Category WildcardSubscribe to all events in a categorycard.* (matches card.activated)
Global WildcardSubscribe to all events*
Using card.* means your webhook will automatically receive new card event types as they are introduced, without needing to update your subscription.

Standard Payload Structure

Every webhook event, regardless of type, follows the same top-level structure:
FieldTypeRequiredDescription
api_versionstringYesAPI version — currently "v1"
event_idstring (UUID)YesUnique identifier for this event. Use for idempotency.
event_categorystringYesCategory of the event (e.g., "kyc", "card")
event_typestringYesSpecific event type (e.g., "kyc.status.changed")
user_idstring (UUID)YesBaanx internal identifier for the user
user_external_idstringNoYour external user identifier, if provided during onboarding
event_object_idstringYesID of the object that changed
event_object_statusstringNoCurrent status of the changed object
event_object_changesobjectNoBefore/after values of the fields that changed
event_objectobjectYesEvent-specific data — contents vary by event type
occurred_atstring (ISO 8601)YesTimestamp of when the event occurred

Example Payload

{
  "api_version": "v1",
  "event_id": "c386021a-d7a5-4aff-8924-4374f1d1d84f",
  "event_category": "kyc",
  "event_type": "kyc.status.changed",
  "user_id": "ecf74983-b52f-40ff-8a4c-aa052748459b",
  "user_external_id": "your-user-id-123",
  "event_object_id": "ecf74983-b52f-40ff-8a4c-aa052748459b",
  "event_object_status": "completed",
  "event_object_changes": {
    "status": ["pending", "completed"]
  },
  "event_object": {
    "status": "completed",
    "failure_code": null,
    "failure_reason": null
  },
  "occurred_at": "2026-01-06T14:50:31.481Z"
}

User Identification

Every webhook includes user_id, the Baanx internal identifier for the user. If you provided an external user ID when onboarding the user, it will also be present as user_external_id in all webhook events for that user.
{
  "user_id": "ecf74983-b52f-40ff-8a4c-aa052748459b",
  "user_external_id": "your-internal-user-id-456"
}
This lets you correlate webhook events with users in your own system without making additional API calls.
user_external_id is set once during user onboarding and remains consistent across all webhooks for that user.

The event_object_changes Field

When a field changes, event_object_changes provides a before/after snapshot as a two-element array — [previous_value, new_value]:
"event_object_changes": {
  "status": ["pending", "completed"]
}
This makes it straightforward to see exactly what changed without needing to store previous state on your side.

Idempotency

Events may occasionally be delivered more than once due to retries or network conditions. Always use event_id as an idempotency key to avoid processing the same event twice:
async function handleWebhook(event) {
  const alreadyProcessed = await db.findEvent(event.event_id);
  if (alreadyProcessed) {
    return { status: 204 }; // Acknowledge without reprocessing
  }

  await processEvent(event);
  await db.markEventProcessed(event.event_id);
  return { status: 204 };
}

Next Steps