API reference
Four AOA event endpoints: a list filtered by city and category, details, ticket types with prices and live seat availability. No key required.
Four read endpoints. A key is optional, but with one the limit is higher. Only published public events that haven’t ended yet are shown.
GET/events
curl "https://aoa.com.ua/api/v1/events?city=Київ&category=workshop&limit=20" \
-H "Authorization: Bearer aoa_live_…"| Parameter | Type | Description |
|---|---|---|
city | string | City name as AOA stores it, in Ukrainian. The match is exact and case-insensitive: “Київ” works, while “Kyiv”, “Киев” or “Ки” don’t. |
category | string | Event category. An unknown value returns 400 with the list in the message. |
limit | integer | How many events to return. 50 by default, 100 at most. |
No pagination
One request returns at most 100 events; there’s no offset or cursor yet. If you need a full catalog larger than that, write to us.dj-set, live-music, party, book-event, performance, art-exhibition, market, workshop, lecture, networking, open-space, movie-screening, other
{
"data": [
{
"id": "a1b2c3",
"url": "https://aoa.com.ua/events/a1b2c3",
"title": "Джаз-вечір",
"startAt": "2026-08-15T18:00:00.000Z",
"endAt": "2026-08-15T22:00:00.000Z",
"imageUrl": "https://aoa.com.ua/uploads/events/cover.jpg",
"eventType": "live_music",
"status": "published",
"city": "Київ",
"venue": "Coffee Lab"
}
],
"meta": { "count": 1, "total": 1, "limit": 20 }
}meta.total is how many events matched the filters, meta.count is how many were returned within the limit. Every field except id, url and title can be null. Events are sorted by start date.
GET/events/{eventId}
For eventId you can use either the short identifier from the link or the full internal one.
{
"data": {
"id": "a1b2c3",
"url": "https://aoa.com.ua/events/a1b2c3",
"title": "Джаз-вечір",
"description": "Живий джаз у затишному просторі",
"imageUrl": "https://aoa.com.ua/uploads/events/cover.jpg",
"startAt": "2026-08-15T18:00:00.000Z",
"endAt": "2026-08-15T22:00:00.000Z",
"allDay": false,
"eventType": "live_music",
"status": "published",
"attendanceMode": "offline",
"capacity": 120,
"location": {
"name": "Coffee Lab",
"address": "вул. Хрещатик, 1",
"city": "Київ"
},
"organizer": {
"name": "Coffee Lab",
"url": "https://aoa.com.ua/o/coffee-lab"
},
"refundPolicy": {
"refundsEnabled": true,
"refundDeadlineHours": 24
},
"ticketTypes": [ … ]
}
}A few things to keep in mind:
organizer is always present. If the event wasn’t created on behalf of an organization, it will be AOA.location can be null, for example when no address has been added yet.ticketTypes repeats what the separate endpoint returns: if you only need tickets, use that one, the response is smaller.410, an unpublished one 404.GET/events/{eventId}/ticket-types
{
"data": [
{
"id": "clx9ticket001",
"name": "Standard",
"priceMinor": 45000,
"priceDecimal": "450.00",
"currency": "UAH",
"isFree": false,
"capacity": 100,
"sold": 37,
"remaining": 63,
"salesStart": "2026-07-01T00:00:00.000Z",
"salesEnd": "2026-08-15T17:00:00.000Z",
"status": "on_sale"
}
],
"meta": { "count": 1 }
}Do your math on priceMinor: it’s kopiyky (hundredths of a hryvnia) as an integer. priceDecimal is for display only. The isFree field is true both for a zero price and for a type with no price.
capacity: null means a type with no seat limit. Then remaining is null too, and that’s not an error.
| status | Meaning |
|---|---|
on_sale | On sale now |
sold_out | No seats left |
sales_not_started | Sales haven’t started yet |
sales_ended | Sales have ended |
Types the organizer has hidden on the event page aren’t returned by the API.
GET/events/{eventId}/availability
The freshest numbers. Unlike ticket-types, this accounts for active holds and unfinished payments, so the number shows how many tickets can really be bought right now.
{
"data": {
"eventId": "a1b2c3",
"ticketTypes": {
"clx9ticket001": 63,
"clx9ticket002": 0
},
"checkedAt": "2026-07-30T12:34:56.789Z"
}
}ticketTypes is an object where the key is the type identifier and the value is the number left. Types with no seat limit are missing from it.
An empty response is ambiguous
An emptyticketTypes: {} means either that the event has no types with a seat limit, or that the availability service is temporarily down. You can’t tell these cases apart from the response, so don’t read an empty object as “sold out”: check against ticket-types.This is the cheapest way to refresh availability: one response covers every ticket type of the event.