Quickstart
The shortest server-side path from app registration to a fulfilled test payment.
Compatible with the closed-beta ATM app APIs and versioned ATM event headers. Check atm-api-version on every webhook or XRPC receiver event.
1. Register your app
App registration adds the app role to your DID and creates separate test and live environments. Webhook URLs are optional at first: ATM still creates a signing secret and queues events until you add an endpoint.
During closed beta, app registration is gated. Invited apps can register from the ATM dashboard or a direct registration link.
Choose whether the app starts with app-fee payouts, direct payments for its own products or subscriptions, or both. Every external app uses one merchant-capable payment setup; this choice only decides which ATM surfaces and defaults are emphasized first. The app stays in the App role unless it separately opts into creator-style recipient surfaces.
2. Configure your test environment
- Choose the ATM modules your app needs.
- Add a webhook URL or XRPC receiver when you have one.
- Copy the environment-specific signing secret.
- Send a test event from the app dashboard.
- Use the dashboard delivery log to inspect or redrive events.
3. Use the App Node SDK
ATM's closed-beta package is @atmosphere-money/app-node. It is a server package, not a Next.js-specific package. Use it from any trusted backend that can keep app secrets private, mint service-auth JWTs, create checkout envelopes, and verify ATM events.
import { createAtmAppClient } from "@atmosphere-money/app-node";
const client = createAtmAppClient({
getServiceAuthToken: async ({ lxm, aud }) => {
return mintMyAppServiceAuthJwt({ lxm, aud });
},
});4. Request creator approval
If your app accepts payments for a creator or organizer, request approval for the app, environment, payment types, fee cap, and public-record behavior before showing an active checkout button.
const approval = await client.requestRecipientApproval({
recipientDid: "did:plc:creator",
environment: "test",
paymentTypes: ["shop"],
feeShareBps: 300,
publicRecords: {
defaults: {
appRecord: "private",
attestation: "private"
}
},
requestReason: "Enable Example App checkout"
});
if (approval.status !== "approved") {
return approval.dashboardUrl;
}5. Call payout status before checkout
Apps should never send buyers to checkout if the recipient is not ready to receive payments. Call payout status first and show a friendly disabled state when setup is incomplete.
GET /xrpc/money.atmosphere.actor.getPayoutStatus?actor=did:plc:creator
Authorization: Bearer <app service-auth jwt>6. Start checkout
ATM follows the strict attested.network initiate route. The request body contains only the broker-defined product value. For ATM, that value is an atm.checkout.v1: envelope.
{
"product": "atm.checkout.v1:<private-envelope>"
}7. Fulfill from ATM truth
Browser redirects can race with processor and proof writes. Treat webhooks, XRPC receiver events, and status polling as the source of truth for fulfillment.
- Receive
payment.completed. - Verify the event signature or service-auth envelope.
- Deduplicate by delivery id and ATM payment id.
- Fulfill the order in your app.
- Optionally poll status on browser return to update the UI.