# ATM Integration

ATM is the payment broker and settlement layer. Tickets uses its checkout
engine; event apps do not create a second processor/payment backend.

## Catalog and event identity

Public ticket types anchor to `community.lexicon.calendar.event`. Paid type
configuration requires an exact active organizer-owned `kind=ticket` Product
with a one-time default Price matching the type's amount/currency. Supply
`product` to `createTicketType`/`updateTicketType`; ATM derives `defaultPrice`,
so omit that legacy input when supplying Product. Free/RSVP types may omit
Product. Public display copies are not settlement authority.

Published SDK beta.5 still types/sends `productRef`/`priceRef`, which do not
satisfy ATM's `product` wire field. Use authenticated raw XRPC for paid type
creation and updates until the coordinated SDK release.

Checkout lists on the ticketType record URI. It freezes exact catalog and
monetary snapshots and revalidates the paid Product/Price graph; apps must not
substitute a Product/Price URI as the ticket listing or derive charges from
AppView display data.

## Paid checkout

1. Read `getTicketAvailability` and select `ticketTypes`.
2. Call `createTicketHold` with `items: [{ ticketTypeId, quantity }]`, a stable
   idempotency key, and either both verified buyer fields or neither.
3. Save `holdId` and private `statusToken` on the server; redirect to the returned
   top-level `url`. Do not look for `hold.checkout.url`.
4. Fulfill after `tickets.issued` or an authorized issued-ticket read. Browser
   returns and payment initiation are insufficient.

ATM ticket checkout uses `paymentType = ticket`. Private broker metadata
includes `commerce_kind`, `ticket_hold_id`, `ticket_event_id`,
`ticket_event_uri`, safe event display snapshots, and `ticket_types`.
Entitlement/catalog refs must be safe public refs, never private issued-ticket
ids. Buyer contact, answers, QR secrets, assertions and promo counters stay
private and must not be copied into public payment proofs.

## Zero-price paths and codes

A zero-price type uses `claimFreeTicket`, required buyer assertion and fresh
private delivery email. It creates no checkout, payment row or public payment
proof. `releaseFreeTicket` is its authenticated inverse for active free claims.

A paid type discounted with a Free/100%-off coupon follows normal $0 checkout
and settlement, creates a $0 payment row and private audit, and publishes no
payment proof. New comp-code creation is retired; existing comp codes have a
private wind-down path. Ticket coupons are separate from generic catalog
discounts, and price coupons are separate from hidden-type access codes.
Organizer event codes can combine access and pricing; their managed redemption
budget counts ticket quantities rather than orders. Send `eventCode` through
the raw current contract when a published SDK does not yet type it.

## Notifications and dashboards

ATM processes settled payments, guarded expiry/cancellation, refunds and voids.
Tickets maintains issuance and admission state and queues retryable app events
through ATM's configured HTTP webhook or optional XRPC receiver. Do not route
private events using arbitrary URLs in public records.

Ticket money stays in unified ATM payment views. Count attendance from issued
tickets, since free claims have no payment row. Revenue aggregates exclude
zero-amount rows. The current organizer console and app control plane are
explained in [ATM_DASHBOARD.md](ATM_DASHBOARD.md).
