Payment lifecycle
How an app-originated checkout becomes a settled ATM payment, app event, receipt, and attested-network proof state.
Compatible with the closed-beta ATM app APIs and versioned ATM event headers. Check atm-api-version on every webhook or XRPC receiver event.
Lifecycle overview
Apps should think of ATM checkout as a state machine. The browser redirect keeps the buyer oriented, but app fulfillment comes from ATM events after the payment is confirmed.
- Preflight
App
Check payability and create a private app order or checkout context.
- Initiate
App -> ATM
Call network.attested.payment.initiate with an ATM checkout envelope.
- Checkout
ATM
Create the hosted checkout session and return a checkout URL.
- Payment
Buyer
Complete payment with card, Link, Apple Pay, Google Pay, or another enabled method.
- Settle
ATM
Create or update the payments ledger row only after money actually occurs.
- Fulfill
ATM -> App
Emit payment.completed and wait for the app to fulfill idempotently.
- Prove
ATM/PDS
Write or reconcile attested-network proof slots asynchronously.
Browser return versus fulfillment
| Browser return | Best for showing confirmation, processing, canceled, or retry UI. It can happen before all webhooks are processed. |
|---|---|
| Status polling | Good for smoothing redirect races. Poll ATM status while waiting for a settled or terminal state. |
| payment.completed | The app fulfillment trigger. Treat this as the durable signal that the app can deliver the order. |
| App dashboard logs | Use delivery logs and redrive to repair app receiver failures without making buyers retry payment. |
Ledger rows
ATM separates checkout attempts from payments. In-progress or failed checkout attempts belong in the private session layer. The visible payments ledger should show payments that actually occurred.
checkout_sessions
- checkout token
- return/cancel URLs
- processor session ids
- in-flight errors
payments
- settled amount
- recipient and payer context
- app-visible ids
- refund/dispute state
subscriptions
- durable recurring relationship
- current amount
- status
- renewal linkage
App events
ATM emits app events after state changes. Apps can receive them through HTTP webhooks, optional XRPC receivers, or both.
| payment.completed | Fulfill a one-time payment, product purchase, commission, ticket purchase, or first subscription payment. |
|---|---|
| payment.refunded | Reverse or flag fulfillment according to app policy. |
| payment.disputed | Pause or review fulfillment when a dispute opens. |
| subscription.updated | Update visible subscription state and benefits. |
| product.archived | Hide a product from sale while preserving historical order state. |
Proof jobs
Proof writing is observable and retryable, but it should not be the app's fulfillment trigger. A payment can be valid for fulfillment while a payer or creator proof waits on OAuth, PDS availability, or delegated app writes.
| Broker proof | ATM writes the ATM broker/rail proof for ATM-processed payments. |
|---|---|
| Payer record | Written by the app, ATM with an existing grant, or left upgradeable for guest/non-delegated payments. |
| Creator proof | Written by ATM when the creator has authorized ATM to write payment proofs. |
| Outbox state | Queued, writing, written, waiting, blocked, or invalidated states belong in proof_write_jobs. |
Retries and reconciliation
- Use an app idempotency key for every order or checkout attempt.
- Store ATM payment ids beside app order ids.
- Deduplicate event delivery ids before sending emails, tickets, downloads, or messages.
- If the processor shows a charge but the ATM ledger is missing, use reconciliation rather than asking the buyer to pay again.
- If an app receiver fails, fix the receiver and redrive the stored delivery.