EventsLocationsSpacesSolutionsPricingIntegrationsAPIBlogHelp
EventsLocationsSpacesSolutionsPricingIntegrationsAPIBlogHelp
© 2026 AOA
Getting startedArtistsFor artistsOrganizersVenuesPast eventsCareersPartnersBubble avatarBento pageGitHub
AboutWhat is AOAPrivacySecurityTermsMerchantCookies
Pricing
UAEN
PricingSupport
FOR PEOPLE
People nearbyHow it worksAOA ConnectSuspended coffee
FOR BUSINESS
VenuesOrganizersFor space ownersFor artists and bands
Solutions
Event check-inEvent networkingTelegram botBento pageLoyalty programSuspended coffeeNFC tags for venues
Extend AOA
IntegrationsAPI & SDK
Help centerDocumentationBlogAbout AOAContact

API reference

  • Introduction
  • Authentication
  • Sandbox
  • Rate limits
  • Errors
  • Versioning
  • Events
  • Reservations
  • Checkout

Webhooks

  • Introduction
  • Event types
  • Verifying signatures
  • Make, Zapier, n8n

API reference

Sandbox

The AOA API sandbox: the same endpoints on test data, a test key with no sign-up, test payments and webhooks with no real bookings or charges.

The sandbox is a copy of the public API on made-up data: https://aoa.com.ua/api/sandbox/v1. The same paths, parameters, response format, error codes and rate limit headers as /api/v1, so an integration tested here moves to the live API by swapping the base URL and the key.

Bookings, ticket holds and payments go all the way through their statuses, but with no side effects: no database records, emails, venue notifications or charges. Sandbox state lives for one day.

Test key

Reading works without a key, just like in the live API. Writing needs a test key, and nobody has to issue it: it’s any string with the aoa_test_ prefix and at least 16 random characters after it. The key only separates your test orders and webhooks from everyone else’s, so make it random. The sandbox rejects live aoa_live_ keys with 401.

Shell
# Make up the test key yourself: the prefix plus at least 16 random characters
export AOA_API_KEY="aoa_test_$(openssl rand -hex 16)"

Test data

IdWhat it isWhat it tests
sbx-cafeA café with table booking, up to 8 guests, closed on MondaysTime slots, a table booking, reason: "closed" on Monday
sbx-barA bar without online bookingreason: "disabled", a refused booking
sbx-lectureA free lecturecheckout for free tickets returns 400
sbx-concertA concert: sbx-concert-standard on sale, sbx-concert-vip sold out, sbx-concert-early with sales endedPayment, 409 on a sold-out ticket, 400 when sales have ended
sbx-workshopA workshop with sales not started yetstatus: "sales_not_started" and 400 on checkout

Ticket stock in the sandbox is fixed: every integration shares it, so someone else’s hold mustn’t sell out the tickets your test needs.

Payment from start to finish

paymentUrl from checkout leads to a test payment page with “Pay” and “Decline” buttons. An agent can also finish the payment on its own, without a person, with an endpoint the live API doesn’t have:

POST/orders/{paymentId}/simulate
cURL
# 1. Sandbox events (no key needed)
curl "https://aoa.com.ua/api/sandbox/v1/events"

# 2. Pay for a ticket: the same request as against the live API
curl -X POST "https://aoa.com.ua/api/sandbox/v1/checkout" \
  -H "Authorization: Bearer $AOA_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"eventId": "sbx-concert",
       "tickets": [{"ticketTypeId": "sbx-concert-standard", "quantity": 2}],
       "buyer": {"email": "test@example.com", "name": "Test Buyer"}}'

# 3. Finish the payment without a person: "paid" or "failed"
curl -X POST "https://aoa.com.ua/api/sandbox/v1/orders/<paymentId>/simulate" \
  -H "Content-Type: application/json" -d '{"outcome": "paid"}'

# 4. Status, just like in the live API
curl "https://aoa.com.ua/api/sandbox/v1/orders/<paymentId>" -H "Authorization: Bearer $AOA_API_KEY"

An unpaid order becomes EXPIRED after 15 minutes, just like a real one. Prefer: respond-async returns 202 with a Location pointing to the sandbox status.

Webhooks

Endpoints are created, updated and deleted with the same requests as in the live API. There’s one difference: the sandbox doesn’t send requests to your URL. Every event (a payment, a decline and a test event of any type) is stored as a ready-made request, and you replay it on your server. The AOA-Signature is computed with the endpoint’s secret at the moment you read it, so the 5-minute window check passes, and the same code then works unchanged in production. Fields of every event are described in Webhook events.

EndpointWhat it does
GET/webhooks/{endpointId}/deliveriesThe last 20 deliveries with body and headers
POST/webhooks/{endpointId}/testA test event of the chosen type with sample data
cURL
# Endpoint: the sandbox remembers it but never sends anything to it
curl -X POST "https://aoa.com.ua/api/sandbox/v1/webhooks" \
  -H "Authorization: Bearer $AOA_API_KEY" -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/hooks/aoa", "events": ["order.paid", "event.cancelled"]}'

# A test event of any type the endpoint is subscribed to
curl -X POST "https://aoa.com.ua/api/sandbox/v1/webhooks/<endpointId>/test" \
  -H "Authorization: Bearer $AOA_API_KEY" -H "Content-Type: application/json" \
  -d '{"type": "event.cancelled"}'

# Deliveries: body, AOA-Signature and the other headers exactly as in production
curl "https://aoa.com.ua/api/sandbox/v1/webhooks/<endpointId>/deliveries" -H "Authorization: Bearer $AOA_API_KEY"

SDKs

The official SDKs work with the sandbox with no code changes: all you need is the sandbox base URL and a test key in AOA_API_KEY.

SDK
// TypeScript
const aoa = createAoaClient({ baseUrl: 'https://aoa.com.ua/api/sandbox/v1' });

# Python
client = AoaClient(base_url="https://aoa.com.ua/api/sandbox/v1")

// Go
client := aoa.NewClient(aoa.WithBaseURL("https://aoa.com.ua/api/sandbox/v1"))

Limits

60 read requests and 30 write requests per minute from one IP address, in the same RateLimit headers. The limit is counted per address, not per key: keys are free, and a new key for every request shouldn’t get around the limit. Every sandbox response carries the AOA-Environment: sandbox header.

PreviousAuthenticationNextRate limits