@aoa-ua/sdk
v0.1.1
Published
Official TypeScript SDK for the AOA public API: venues, table availability and bookings, events, tickets, checkout and webhooks in Ukraine.
Maintainers
Readme
AOA SDK for TypeScript
Official client for the AOA (Act of Attraction) public API: venues and table bookings, events and tickets, checkout, orders and webhooks in Ukraine.
- One typed method per
operationIdof the OpenAPI spec; the types are generated from the spec. - Zero runtime dependencies; uses global
fetchand WebCrypto. Node.js 20+, Bun, Deno, edge runtimes. ESM only. - Automatic
Idempotency-Keyfor table bookings and checkout, opt-in429retries honouringRetry-After, rate-limit state, cursor pagination, webhook signature verification.
npm install @aoa-ua/sdkQuick start
import { createAoaClient } from '@aoa-ua/sdk';
// Reads need no key. The key (aoa_live_...) is needed for writes and raises
// read limits from 60 to 600 requests per minute. Defaults to AOA_API_KEY.
const aoa = createAoaClient({ apiKey: process.env.AOA_API_KEY });
const { data: venues } = await aoa.searchLocations({ city: 'Київ', limit: 5 });
const { data: day } = await aoa.getTableAvailability({
locationId: venues[0].id,
date: '2026-10-03',
});
const free = day.slots?.filter((slot) => slot.available).map((slot) => slot.value);Book a table (after the person confirmed)
const { data: booking } = await aoa.createTableReservation(
{
locationId: venues[0].id,
date: '2026-10-03',
time: '19:00',
partySize: 2,
guest: { name: guestTypedName, phone: guestTypedPhone }, // typed by the person
confirmedByUser: true, // only after an explicit yes
},
{ idempotencyKey: `booking-${cartId}` }, // generated when omitted
);
// booking.status: pending until the venue confirmsSell tickets
const { data: stock } = await aoa.getEventAvailability({ eventId: 'a1b2c3' });
const { data: checkout } = await aoa.createTicketCheckout(
{
eventId: 'a1b2c3',
tickets: [{ ticketTypeId: 'tt_…', quantity: 2 }],
buyer: { email: buyerEmail, name: buyerName },
},
{ idempotencyKey: `order-${orderId}`, timeoutMs: 30_000 },
);
// Send the person to checkout.paymentUrl, then poll:
const { data: order } = await aoa.getOrder({ paymentId: checkout.paymentId });Errors, limits, retries
import { AoaApiError } from '@aoa-ua/sdk';
const aoa = createAoaClient({ maxRetries: 2 }); // retry 429 after Retry-After
try {
await aoa.getEvent({ eventId: 'missing' });
} catch (error) {
if (error instanceof AoaApiError) {
error.status; // 404
error.code; // 'not_found' (branch on this, not on message)
error.hint; // what to do next, when known
error.retryable; // true for rate_limited and internal_error
}
}
aoa.rateLimit; // { limit, remaining, resetSeconds, windowSeconds } of the last responsePagination
for await (const event of aoa.paginate('searchEvents', { city: 'Львів' })) {
console.log(event.title, event.url);
}paginate follows meta.nextCursor and stops after one page when the server
returns none.
Webhooks
import express from 'express';
import { constructWebhookEvent } from '@aoa-ua/sdk';
app.post('/hooks/aoa', express.raw({ type: 'application/json' }), async (req, res) => {
try {
const event = await constructWebhookEvent(
req.body, // raw bytes: never re-serialized JSON
req.get('AOA-Signature'),
process.env.AOA_WEBHOOK_SECRET!,
);
res.sendStatus(200);
void handle(event); // deduplicate by event.id (= AOA-Delivery-Id)
} catch {
res.sendStatus(401);
}
});Several reads in one request
const { data: results } = await aoa.batchOperations({
operations: [
{ id: 'first', path: '/events/AB12CD34/availability' },
{ id: 'second', path: '/events/EF56GH78/availability' },
],
});
// results[i]: { id, status, body }, in the same order; up to 20 operationsAsynchronous checkout
const result = await aoa.createTicketCheckout(params, {
headers: { Prefer: 'respond-async' }, // 202 with data.statusUrl
});Any operation by id
const result = await aoa.request('getEventTicketTypes', { eventId: 'a1b2c3' });Development
npm install
npm run generate:fetch # download https://aoa.com.ua/openapi.json, update the snapshot and types
npm test # stale-types check, build, type tests, node --testsrc/generated/schema.ts is generated by scripts/generate-types.mjs; do not
edit it by hand. A new API operation needs no SDK code: regenerate and it
appears as a typed method.
Links
- Docs: https://aoa.com.ua/docs
- Repository: https://github.com/aoa-ua/aoa-agent-kit
- License: MIT
