---
title: "Пісочниця · API Reference: документація AOA API"
description: "Пісочниця (sandbox) API AOA: ті самі ендпоінти на тестових даних, тестовий ключ без реєстрації, тестова оплата й вебхуки без справжніх бронювань і платежів."
canonical: "https://aoa.com.ua/docs/api-reference/sandbox"
---

# Пісочниця

Пісочниця (sandbox) API AOA: ті самі ендпоінти на тестових даних, тестовий ключ без реєстрації, тестова оплата й вебхуки без справжніх бронювань і платежів.

Пісочниця це копія публічного API на вигаданих даних: `https://aoa.com.ua/api/sandbox/v1`. Ті самі шляхи, параметри, формат відповідей, коди помилок і заголовки лімітів, що й у `/api/v1`, тож інтеграцію, перевірену тут, переводять на живий API заміною базового URL і ключа.

Бронювання, утримання квитків і оплати проходять повний шлях зі статусами, але без наслідків: жодного запису в базі, листа, повідомлення закладу чи платежу. Стан пісочниці живе добу.

## Тестовий ключ

Читання працює без ключа, як і в живому API. Для запису потрібен тестовий ключ, і видавати його не треба: це будь-який рядок з префіксом `aoa_test_` і щонайменше 16 випадковими символами після нього. Ключ лише відокремлює ваші тестові замовлення й вебхуки від чужих, тож робіть його випадковим. Живі ключі `aoa_live_` пісочниця відхиляє з 401.

```
# Тестовий ключ придумуєте самі: префікс і щонайменше 16 випадкових символів
export AOA_API_KEY="aoa_test_$(openssl rand -hex 16)"
```

## Тестові дані

| Id | Що це | Що перевіряє |
| --- | --- | --- |
| `sbx-cafe` | Кавʼярня з бронюванням, до 8 гостей, понеділок вихідний | Слоти, бронь столика, reason: "closed" у понеділок |
| `sbx-bar` | Бар без онлайн-бронювання | reason: "disabled", відмову створити бронь |
| `sbx-lecture` | Безкоштовна лекція | checkout безкоштовних квитків повертає 400 |
| `sbx-concert` | Концерт: «Стандарт» у продажу, «VIP» розпроданий, «Ранній» з завершеним продажем | Оплату, 409 на розпроданий квиток, 400 на завершений продаж |
| `sbx-workshop` | Воркшоп, продаж ще не почався | status: "sales_not_started" і 400 на checkout |

Залишки квитків у пісочниці сталі: її ділять усі інтеграції, тож чуже утримання не має розпродати квитки вашому тесту.

## Оплата від початку до кінця

`paymentUrl` з checkout веде на тестову сторінку оплати з кнопками «Оплатити» і «Відхилити». Агент може завершити оплату й сам, без людини, ендпоінтом, якого в живому API немає:

**POST** `/orders/{paymentId}/simulate`

```bash
# 1. Події пісочниці (ключ не потрібен)
curl "https://aoa.com.ua/api/sandbox/v1/events"

# 2. Оплата квитка: той самий запит, що й до живого 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": "Тест Тестенко"}}'

# 3. Завершити оплату без людини: "paid" або "failed"
curl -X POST "https://aoa.com.ua/api/sandbox/v1/orders/<paymentId>/simulate" \
  -H "Content-Type: application/json" -d '{"outcome": "paid"}'

# 4. Статус, як у живому API
curl "https://aoa.com.ua/api/sandbox/v1/orders/<paymentId>" -H "Authorization: Bearer $AOA_API_KEY"
```

Неоплачене замовлення через 15 хвилин стає `EXPIRED`, як і справжнє. `Prefer: respond-async` дає 202 з `Location` на статус пісочниці.

## Вебхуки

Endpoint-и створюються, змінюються й видаляються тими самими запитами, що в живому API. Різниця одна: пісочниця не надсилає запитів на вашу адресу. Кожна подія (оплата, відмова і тестова подія будь-якого типу) зберігається як готовий запит, і ви відтворюєте його на своєму сервері. Підпис `AOA-Signature` рахується секретом endpoint-а в момент читання, тож перевірка з вікном у 5 хвилин проходить, і її код потім без змін працює в продакшені. Опис полів кожної події: [Події вебхуків](https://aoa.com.ua/docs/webhooks/events).

| Ендпоінт | Що робить |
| --- | --- |
| **GET** `/webhooks/{endpointId}/deliveries` | Останні 20 доставок з тілом і заголовками |
| **POST** `/webhooks/{endpointId}/test` | Тестова подія обраного типу з прикладом даних |

```bash
# Endpoint: пісочниця запамʼятає його, але нікуди не надсилає
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"]}'

# Тестова подія будь-якого типу, на який підписаний endpoint
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"}'

# Доставки: тіло, AOA-Signature і решта заголовків рівно такі, як у продакшені
curl "https://aoa.com.ua/api/sandbox/v1/webhooks/<endpointId>/deliveries" -H "Authorization: Bearer $AOA_API_KEY"
```

## SDK

Офіційні SDK працюють з пісочницею без змін у коді: достатньо базового URL пісочниці і тестового ключа в `AOA_API_KEY`.

```
// 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"))
```

## Ліміти

60 запитів на хвилину на читання і 30 на запис з однієї IP-адреси, у тих самих заголовках `RateLimit`. Ліміт рахується за адресою, а не за ключем: ключ безкоштовний, і новий ключ на кожен запит не мав би обходити ліміт. Кожна відповідь пісочниці несе заголовок `AOA-Environment: sandbox`.
