Webhook Confirmations
Elements callbacks keep the browser moving. Signed webhooks are what your backend uses to reconcile links, card storage, and payment attempts after tabs close, mobile WebViews background, or networks drop.
Callbacks are UX signals
Never fulfill from a browser callback alone
onSuccess, redirect URLs, and hosted-page completion screens run in user-controlled clients. Use them to update UI and send identifiers to your server, but verify signatures and dedupe webhook event IDs before changing durable server state.Confirmation paths by flow
| Flow | Browser signal | Durable confirmation | Webhook types |
|---|---|---|---|
| Interactive Connect | onSuccess(public_token) | Your server exchanges the public token, then reconcile link.completed. connection.ready and bill.created confirm the first retrieval. | link.completedconnection.readybill.created |
| Hosted/background Connect | Hosted page completion or redirect | Use link_token.completed as the durable server-side confirmation that BillerAPI completed the background exchange and created the link. | link_token.completedconnection.readybill.created |
| Add Card | onSuccess(payment_method_id) | No money moves and no payment webhook is emitted for card storage today. Persist the payment_method_id server-side, then wait for pay.* only when that method is used to pay a bill. | No storage webhook today |
| Pay | onSuccess(payment_attempt_id) | pay.scheduled confirms the attempt entered processing. A terminal signed webhook, not the browser callback, decides fulfillment. | pay.scheduledpay.succeededpay.failedpay.escalated |
Connect reconciliation
Interactive Connect returns a public_token to the browser so your backend can exchange it. Background Connect does the exchange inside BillerAPI and emits link_token.completed. In both paths, wait for signed link and bill webhooks before assuming bill data is ready.
Ready is separate from linked
link.completed means the link exists.connection.ready and bill.created tell you the first bill retrieval has produced usable data.Add Card reconciliation
Add Card returns a tokenized payment_method_id plus display-safe metadata. That is a stored method, not a paid bill. Because there is no payment attempt, BillerAPI does not emit a pay.* webhook for Add Card by itself.
Do not infer money movement
payment_method_id for later use, but keep fulfillment logic tied to Pay terminal webhooks.Pay outcomes
pay.scheduledThe payment attempt was accepted into the processing lifecycle. Keep the bill in a pending or processing state.
pay.succeededThe attempt reached paid state. Mark the bill paid only after deduping and verifying this signed event.
pay.failedThe attempt failed. Surface the failure and let the customer retry with a valid bill or payment method.
pay.escalatedThe attempt needs human review. Keep the customer out of a false paid state and show a review/pending status.
Production Pay gate
PAY_EXECUTE_ENABLED. While the gate is off, production payment initiation returns PAYMENT_EXECUTION_NOT_AVAILABLE; use sandbox to test pay.* reconciliation.