Callbacks
Receive ticket events.
Configure signed webhooks or optional XRPC receivers, validate payloads, and redrive events safely.
Webhooks
Ticket events are delivered to the app endpoints configured in ATM app settings. Public ticket records should not contain arbitrary webhook URLs. Handlers must be idempotent because ATM can retry or redrive delivery.
ticket.hold.created
ticket.hold.expired
tickets.issued
ticket.refunded
ticket.voided
ticket.checked_in
ticket.form_submitted
ticket.waitlist.offered
ticket.collaboration.invited
ticket.collaboration.accepted
ticket.collaboration.revoked
Receiver options
HTTP webhooks are the default because any app can host them. AT Protocol-native apps may also configure an optional XRPC receiver callback for the same event envelope. In both cases, ATM signs the event and apps verify the signature before side effects.
| Receiver | Best for | Notes |
|---|---|---|
| HTTP webhook | Most integrations | Simple, familiar, durable retries, works for non-XRPC infrastructure. |
| XRPC receiver | AT Protocol-native apps | Same signed envelope, app-hosted XRPC surface, better shape for generated clients. |
| Subscription streams | Future live ops | Useful later for scanner rooms, live availability dashboards, and agentic monitoring. |
POST https://app.example/xrpc/money.atmosphere.event.receive
Authorization: Bearer <atm service-auth jwt>
{
"id": "evt_...",
"deliveryId": "del_...",
"type": "tickets.issued",
"environment": "test",
"data": { "eventUri": "at://...", "issuedCount": 2 }
}
Webhook test console
Build a local test command for signed HTTP webhooks or optional XRPC receivers. Real delivery status and redrive still live in the ATM app dashboard.
curl -X POST "https://your-app.example/webhooks/atm" \
-H "ATM-Signature: t=...,v1=..." \
-H "Content-Type: application/json" \
--data '{"type":"tickets.issued","environment":"test","deliveryId":"del_test_123","data":{"eventUri":"at://..."}}'
Payload schemas
Ticket events use the same ATM event envelope as payment events: event id, delivery id, environment, type, app DID, createdAt, and a typed data payload. App handlers should branch on the event type and validate the data payload before side effects.
| Payload | Required fields | Notes |
|---|---|---|
| ticket.hold.created | holdId, eventUri, expiresAt | Capacity is temporarily reserved. |
| ticket.hold.expired | holdId, eventUri | The app should clear pending checkout UI. |
| tickets.issued | eventUri, issuedCount | May include paymentId, buyerDid, and app order refs. |
| ticket.checked_in | ticketId, checkedInAt, checkInListId | Repeat scans should return existing state. |
| ticket.voided | ticketId, reason | Pass tokens should no longer admit entry. |
{
"id": "evt_...",
"deliveryId": "del_...",
"environment": "test",
"type": "tickets.issued",
"appDid": "did:plc:app",
"createdAt": "2026-06-05T00:00:00.000Z",
"data": {
"eventUri": "at://...",
"issuedCount": 2,
"buyerDid": "did:plc:buyer"
}
}
Event catalog
Ticket lifecycle events are delivered through ATM app webhooks or optional XRPC receiver callbacks. Handlers must be idempotent and environment-aware. The table here mirrors the launch event families that ticketing apps subscribe to through the ATM app dashboard.
Capacity reserved
A hold was created before checkout or free claim completion.
Capacity released
A hold expired or was released before payment completed.
Tickets ready
Issued tickets were created after payment confirmation or a free limited claim.
Entry recorded
A scanner verified and checked in a ticket token.
Attendee form saved
Private attendee responses were submitted for an issued ticket.
Capacity reopened
A waitlisted buyer received a temporary offer hold. Never auto-charge.
Organizer collaboration changed
A co-organizer invite, acceptance, or revocation changed operational permissions.
Payment reversed
Ticket status should be reviewed or voided after refund.
Ticket revoked
The issued ticket is no longer valid for entry.