Events and monitoring
Partner events
Every plugin's lifecycle signal is re-exposed on pluginEvents, keyed by item id:
LaunchedEffect(checkout) {
checkout.pluginEvents.collect { (itemId, event) ->
when (event) {
is PluginEvent.InitFailed -> dim(itemId)
is PluginEvent.PartnerError -> if (event.recoverable) banner(itemId)
PluginEvent.Redirect -> leavingAppHint()
else -> Unit
}
}
}
| Event | Meaning | The checkout already… |
|---|---|---|
Ready | The partner's client is up | clears a recoverable disabled state |
Redirect | The shopper is being sent to an external step | |
InitFailed(message) | /init or setup failed before any UI | disables the method (PARTNER_UI_FATAL_ERROR) |
ClientError(message) | The partner's client failed for good | disables the method (PARTNER_UI_FATAL_ERROR) |
PartnerError(message, recoverable) | The partner reported an error | disables the method, or dims it until it recovers when recoverable |
Cancelled | The shopper backed out of the partner's flow | |
EndOfSession | The partner said the session is finished | terminates the session |
You react for the shopper's screen; the method list reacts on its own through its disabled states (Method states).
Your own analytics
Every event the SDK records is also published on a process-wide bus you can subscribe to. By default, subscribe uses Scope.PUBLIC, the same scope as the web SDK's public events, and delivers six codes only: HEADLESS_CHECKOUT_READY, _EXPIRED_SESSION, _PAYMENT_FULFILLED, _OTHER_ERROR, _CLIENT_HOOK_ERROR and _PAYMENT_ERROR. Pass Scope.ALL to receive every code in the table below:
val unsubscribe = CheckoutEventBus.getInstance().subscribe(CheckoutEventBus.Scope.ALL) { event ->
analytics.track(event.code.name, event.payload)
}
Unsubscribe when your screen goes away.
What the SDK reports to Purse
The SDK reports what it does to Purse's monitoring pipeline: the same events, names and envelope as the web Headless Checkout, plus platform: android, so Android journeys appear in the dashboards Purse already runs. Events are batched (16 events, 10 seconds or 64 KB) and flushed when the app goes to the background and on teardown(). A failed batch is dropped silently: telemetry never breaks a payment. Nothing is sent when the session carries no API key.
Each event carries the merchant entity, the session id, a checkout instance id (kept across setSession and restore), the SDK version, the environment and the platform.
| Code | When |
|---|---|
HEADLESS_CHECKOUT_CREATE, _READY | init or restore, with device model, OS version and screen size |
HEADLESS_CHECKOUT_SET_SESSION, _EXPIRED_SESSION | A session is set or refreshed (number of methods), or expires |
HEADLESS_CHECKOUT_METHOD_DISABLED | A method enters a disabled state: partner, method, code, whether filtered or recoverable |
HEADLESS_CHECKOUT_METHOD_SET_PRIMARY, _PRIMARY_TOKEN_SET_AS_PRIMARY, _CLEAR_PRIMARY_SPLIT | Selection |
HEADLESS_CHECKOUT_SECONDARY_TOKEN_TAKE, _REMOVE_FROM_SPLIT, _REGISTER, _METHOD_GET_SECONDARY_TOKEN | Gift cards (whether a slice was partial, never its amount) |
HEADLESS_CHECKOUT_TOKEN_EDIT, _DELETE, _SET_FAVORITE, _DELETE_ALL_TOKENS | Wallet management |
HEADLESS_CHECKOUT_METHOD_LOAN_SIM, _METHOD_REGISTER | BNPL simulation (with the simulated amount and currency), save decision |
HEADLESS_CHECKOUT_PAYMENT_FULFILLED | The split covers the amount, or stops to |
HEADLESS_CHECKOUT_SUBMIT_PAYMENT, _SUBMIT_BLOCKED | A submit entered, or a second one was refused |
HEADLESS_CHECKOUT_VALIDATION_STARTED, _SUCCESS, _FAILED | Around /validate, with each attempt's status codes |
HEADLESS_CHECKOUT_PAYMENT_ERROR | A refused /validate or a thrown submit error, with its code and the failing API path and status |
HEADLESS_CHECKOUT_ON_BEFORE_VALIDATE_HOOK_FAILED, _CLIENT_HOOK_ERROR | One of your hooks threw |
HEADLESS_CHECKOUT_PARTNER_UI_EVENT | Every partner event above |
HEADLESS_CHECKOUT_PARTNER_API_CALL_START, _END | Every Payment API call, with its duration |
HEADLESS_CHECKOUT_UNCAUGHT_ERROR | An SDK coroutine died, with a capped stack trace |
HEADLESS_CHECKOUT_PAGE_UNLOAD | The app went to the background |
What never leaves the device
Not in any event:
- card data (the card form belongs to Secure Fields, its values never reach the SDK), form content, shopper identity;
- raw amounts, with one exception:
HEADLESS_CHECKOUT_METHOD_LOAN_SIMcarries the amount and currency of the simulated loan. Other events say how many methods, or whether a gift card slice was partial, never a figure; - transaction ids and partner payloads:
/validateresults travel as status codes only, and an API error never quotes the response body; - a disabled state's message, which can quote amounts: only its code.
Telemetry is on whenever the session carries an API key. It is scoped to the payment journey and carries no advertising identifier.