First real app tutorial
The canonical app integration route: register, configure test mode, create checkout, receive payment.completed, and fulfill.
Compatible with the closed-beta ATM app APIs and versioned ATM event headers. Check atm-api-version on every webhook or XRPC receiver event.
Goal
This is the canonical ATM app integration path. At the end, the app has a test environment, a receiver, a successful checkout path, and a redrive-safe event handler that fulfills only from ATM truth.
- 01
Register app
Add the app role to the app DID and keep configuration in test mode.
- 02
Configure test
Enable modules, add a receiver, copy the test secret, and subscribe to events.
- 03
Create checkout
Create an app order, build the private ATM checkout envelope, and redirect the buyer.
- 04
Receive event
Verify payment.completed, deduplicate the delivery id, and store the ATM payment id.
- 05
Fulfill
Mark the app order paid and move toward live only after redrive and refund paths pass.
App server
Runs the starter kit or your own equivalent server-side integration.
ATM dashboard
Stores app config, modules, webhooks, delivery logs, and test/live settings.
ATM checkout
Owns the buyer payment form, wallets, receipts, status, and proof coordination.
App fulfillment
Runs only after a verified ATM event or confirmed ATM status.
Prerequisites
- An allowlisted app DID with access to app registration.
- A server runtime that can keep app secrets private.
- A tunnel or deployed test URL for HTTP webhooks.
- A test recipient that has completed payment setup when testing paid checkout.
- A plan for idempotency keys and delivery id deduplication.
1. Register the app
- 01
Sign in
Use the DID that represents the app, not an individual developer's personal account.
- 02
Request app role
ATM adds the app role while preserving payer or creator roles on the same DID.
- 03
Complete profile
Name, avatar, description, and app URL become the app-facing identity in ATM.
- 04
Stay in test
The app dashboard defaults to test configuration for modules, secrets, and receivers.
2. Configure test mode
| Modules | Enable only what the app is testing: payments, products, subscriptions, tickets, or callbacks. |
|---|---|
| Webhook URL | Start with HTTP webhooks unless your app already hosts XRPC methods. |
| Signing secret | Copy the test secret once and store it in server-side env. |
| Event selection | Subscribe to only the events your app knows how to handle. |
| App fee | Set the app fee policy intentionally before any checkout test. |
3. Run the starter kit
The starter kit proves local receiver verification and status handling before you wire application-specific order logic.
cd examples/atm-node-app
cp .env.example .env
npm run build --prefix ../../packages/app-node
npm install
npm run typecheck
npm run smoke
npm run dev
curl http://localhost:8787/healthThe compact source file at docs/developer/examples/happy-path-app.tsshows the same app-order, checkout, webhook, and fulfillment sequence without the full starter-kit HTTP server.
4. Create the first checkout
For a real app, create an app order first, then create the ATM checkout envelope from that order. The browser should receive only the returned ATM checkout URL.
const order = await createAppOrder({
recipientDid,
amountCents: 1200,
currency: "usd"
});
const checkout = await atm.initiatePayment({
environment: "test",
recipient: order.recipientDid,
amount: order.amountCents,
currency: order.currency,
paymentType: "shop",
metadata: { appOrderId: order.id },
returnUrl: "https://app.example/orders/" + order.id,
cancelUrl: "https://app.example/support"
});
return Response.redirect(checkout.url);5. Verify event delivery
Send a dashboard test event first. Then complete a real test checkout and verify that both paths are deduplicated by delivery id.
- The receiver validates `Atm-Signature` over the raw body and `Atm-Delivery-Id`.
- The receiver stores the delivery id before side effects.
- Redriving the same delivery does not fulfill twice.
- The app handles unknown future event fields as additive.
6. Inspect dashboard state
| App dashboard | Check module status, test/live environment, and fee settings. |
|---|---|
| Webhooks | Confirm delivery status, attempts, response code, and redrive action. |
| Payments | Confirm the payment row, app id, app fee fields, customer fields, and proof status. |
| Products or tickets | Confirm linked fulfillment refs or issued ticket state if those modules are enabled. |
7. Ready for live
- Guest and signed-in payer checkout paths pass.
- Webhook and optional XRPC receiver paths pass.
- Failed delivery and redrive pass.
- Refund/cancel/subscription-change paths pass for enabled modules.
- Private data stays off protocol and out of public logs.
- Live secrets are separate from test secrets.