Внешняя система — касса, учётная или гостиничная программа — может забирать меню, читать заказы и счета заведения и передавать нам заказ, который приняла сама. Для этого есть отдельный API: он работает от имени заведения и не требует учётной записи сотрудника.
Адрес — это адрес приложения Qreaty плюс /api/external/v1. В рабочей версии это https://qreaty.com/api/external/v1; готовый адрес показан в разделе «Доступ по API» (как его открыть) — его можно скопировать оттуда. Все запросы ниже даны относительно этого адреса: GET /menu/items значит GET https://qreaty.com/api/external/v1/menu/items.
Ответы — JSON в формате JSON:API (data, attributes), запросы с телом — JSON. Токен передаётся в заголовке Authorization: Bearer <токен>, а Accept: application/json желателен всегда.
Язык. Названия и описания приходят на языке, который вы укажете: параметр ?locale=vi (код языка: ru, en, vi…) или заголовок Accept-Language: vi. Какие языки есть, API говорит само: в каждом ответе GET /menu/items и GET /menu/modifiers есть meta.menus — по каждому меню список locales (на каких языках оно переведено) и source_locale — язык оригинала, на котором владелец вводил меню. Если на запрошенный язык перевода нет (или язык не указан), приходит оригинал.
{primary} Токен принадлежит заведению, а не человеку: уйдёт сотрудник, который его выпустил, — токен продолжит работать, пока вы его не отзовёте. Каждый токен видит только своё заведение.
Что умеет API:
| Что | Запрос | Нужное право токена |
|---|---|---|
| Все блюда | GET /menu/items |
menu:read |
| Группы модификаторов и опции | GET /menu/modifiers |
menu:read |
Столы (id, number, name, zone) |
GET /tables |
orders:read |
| Заказы | GET /orders, GET /orders/{id} |
orders:read |
| Счета | GET /bills, GET /bills/{id} |
orders:read |
| Принять заказ | POST /orders |
orders:write |
Токен выпускает владелец или тот, кто может менять настройки заведения.
{warning} Токен — как пароль: любой, у кого он есть, действует от имени заведения в пределах выданных прав. Не отправляйте его в чатах и не храните в репозитории. Если токен мог утечь — отзовите его в том же разделе и выпустите новый: отозванный перестаёт работать сразу.
Один токен — одна подключённая система. Так видно, кто и когда обращался, и отзыв одной системы не ломает остальные.
Внешняя система называет позиции SKU — кодом, который у неё записан в справочнике. У каждого блюда и у каждой опции модификатора есть SKU, пустым он не бывает:
QR-D<номер> (блюдо) или QR-M<номер> (опция) — он уникален и не меняется.. _ - /.В заказе SKU запоминается вместе с названием: если вы смените код блюда завтра, вчерашние счета останутся с тем кодом, под которым блюдо продали.
{primary} Если у двух блюд одного меню совпал код (так бывает у старых данных, привязанных вручную), API скажет об этом: в ответе
GET /menu/itemsи/menu/modifiersестьmeta.duplicate_skus. Пока дубль не исправлен, заказать такой SKU нельзя — запрос получит ошибку.
GET /menu/items возвращает блюда активного меню — того, по которому заказывают гости и касса, — по 50 за страницу (?per_page= до 200, ?page=). Другое меню можно запросить явно: filter[menu]=<id>; номера меню и их языки есть в meta.menus.
Ключ блюда — его SKU: он же стоит в id и именно его присылают обратно в заказе. У блюда: sku, name, description, price_type (fixed — фиксированная, from — «от», range — диапазон, variable — по запросу) с price_value / price_min / price_max / price_unit, currency, kind (food, drink, alcohol, other), section, available — можно ли заказать прямо сейчас (не скрыто, не в стоп-листе, секция включена), sold_out — стоит ли оно в стоп-листе и modifier_group_ids — какие группы модификаторов к нему привязаны.
Фильтры: filter[available]=1, filter[section], filter[sku], filter[menu], filter[updated_since]=2026-10-14T00:00:00Z — удобно для регулярной сверки: берёте только то, что менялось.
GET /menu/modifiers — группы модификаторов активного меню с опциями. Опция называется своим SKU (options[].sku) и несёт name, price, is_default, max_qty и prices — цена по размеру (driver_option_sku — опция-размер, price — цена при ней). У группы: name, pricing_mode (replace — цена опции заменяет цену блюда, как размер; add — добавляется, как топпинг), required, selection_min / selection_max — сколько опций можно выбрать, item_skus — к каким блюдам группа привязана, parent_option_sku — если группа открывается под опцией другой группы. id группы — её ссылка в modifier_group_ids блюда.
curl -s -g "https://qreaty.com/api/external/v1/menu/items?filter[available]=1&locale=vi" \
-H "Authorization: Bearer $TOKEN" -H "Accept-Language: vi"
{primary} Все запросы ниже собраны в готовую коллекцию для Postman: скачать. Импортируйте файл, впишите токен в переменную коллекции
token— и можно отправлять; SKU и номер стола подставятся сами.
Адрес с фильтрами собирается из частей: путь?filter[имя]=значение&filter[имя2]=значение2. Ниже — готовые строки, которые можно подставлять как есть. В curl добавляйте -g, чтобы квадратные скобки не трактовались как шаблон; в Postman их вводить так же, как здесь. Знак + во времени пишется как %2B (+07:00 → %2B07:00), иначе он превратится в пробел.
| Что нужно | Запрос |
|---|---|
| Все блюда на вьетнамском, по 200 на страницу | GET /menu/items?locale=vi&per_page=200 |
| Только блюда, которые сейчас можно заказать | GET /menu/items?filter[available]=1 |
| Блюдо по его SKU | GET /menu/items?filter[sku]=PHO-1 |
Блюда одного меню (id меню — в meta.menus) |
GET /menu/items?filter[menu]=12 |
| Что изменилось в меню с указанного момента | GET /menu/items?filter[updated_since]=2026-10-14T00:00:00Z |
| Группы модификаторов одного меню | GET /menu/modifiers?filter[menu]=12 |
GET /orders — заказы (раунды счёта), новые сверху. Каждый — со строками, выбранными опциями, статусом, столом, номером и временем. Строка называет блюдо его SKU (lines[].sku), а вложенные опции — lines[].modifiers[].sku.
| Фильтр | Что делает |
|---|---|
filter[status] |
pending, confirmed, completed, rejected, cancelled; несколько — через запятую |
filter[source] |
guest (гость по QR), staff (официант), external (принят по API) |
filter[table] |
номер стола |
filter[bill] |
id счёта |
filter[external_id] |
id заказа в вашей системе |
filter[placed_from], filter[placed_to] |
интервал времени приёма (от — включительно, до — нет) |
filter[updated_since] |
всё, что менялось с указанного момента |
GET /bills — счета столов: сумма, налог, способ оплаты (tender), номер комнаты, когда открыт и закрыт, и список id заказов. С ?embed=orders заказы приходят целиком. Фильтры: filter[status]=open|closed, filter[tender] (cash, transfer, card, ewallet, room_charge, voucher, none — без записанной оплаты), filter[table], filter[number], filter[room_number], filter[opened_from|opened_to], filter[closed_from|closed_to], filter[updated_since]. Сортировка: ?sort=-closed_at.
Время в запросах — ISO 8601 (2026-10-14T09:00:00+07:00); в ответах — тоже.
{primary} Чтобы не терять изменения, храните момент последней успешной выборки и в следующий раз просите
filter[updated_since]с небольшим запасом назад — повторные записи вы всё равно узнаете по id.
Те же правила (-g в curl, %2B вместо +). Время — по вьетнамскому поясу (+07:00).
| Что нужно | Запрос |
|---|---|
| Заказы, ждущие подтверждения | GET /orders?filter[status]=pending |
| Подтверждённые и завершённые | GET /orders?filter[status]=confirmed,completed |
| Заказы за 14 октября | GET /orders?filter[placed_from]=2026-10-14T00:00:00%2B07:00&filter[placed_to]=2026-10-15T00:00:00%2B07:00 |
| Только пришедшие по API | GET /orders?filter[source]=external |
| Подтверждённые заказы стола 5 | GET /orders?filter[table]=6512&filter[status]=confirmed |
| Всё, что менялось после последней сверки, от старых к новым | GET /orders?filter[updated_since]=2026-10-14T09:00:00Z&sort=updated_at |
| Наш заказ по номеру в вашей системе | GET /orders?filter[external_id]=POS-100234 |
| Открытые счета | GET /bills?filter[status]=open |
| Закрытые счета за 14 октября, с заказами и строками внутри | GET /bills?filter[status]=closed&filter[closed_from]=2026-10-14T00:00:00%2B07:00&filter[closed_to]=2026-10-15T00:00:00%2B07:00&embed=orders |
| Счета, записанные на номер отеля | GET /bills?filter[status]=closed&filter[tender]=room_charge |
| Счета конкретной комнаты | GET /bills?filter[room_number]=412 |
| Закрытые счета без записанной оплаты | GET /bills?filter[status]=closed&filter[tender]=none |
| Следующая страница | добавьте &page=2 к любому из запросов |
POST /orders — внешняя система передаёт заказ, который приняла у гостя. Он попадает в заведение как обычный подтверждённый заказ: уходит на кухню и в печать, списывает склад, попадает в счёт стола и аналитику. Цену считаем мы по меню — присылать цены не нужно.
{
"external_id": "POS-100234",
"table": 6512,
"room_number": "412",
"note": "Без кинзы",
"items": [
{
"sku": "PHO-1",
"quantity": 2,
"note": "Острое отдельно",
"modifiers": [
{ "sku": "SIZE-L" },
{ "sku": "EGG", "quantity": 1 }
]
}
]
}
| Поле | Что значит |
|---|---|
external_id |
Номер заказа в вашей системе. Обязателен: по нему повтор запроса распознаётся |
table |
id стола ровно так, как его вернул GET /tables (число вроде 6512; номер стола на табличке — это поле number, оно нужно только чтобы сопоставить ваши столы с нашими) |
room_number |
Номер комнаты, чтобы записать заказ на номер отеля |
served |
true — заказ уже подан: записывается как проведённый, на кухню не идёт |
items[].sku, quantity |
Блюдо и количество (1–99) |
items[].modifiers[] |
Выбранные опции по SKU; вложенные — в их modifiers |
Ответ 201 содержит созданный заказ — с нашим id, номером и ценами.
Повтор безопасен. Если связь оборвалась и вы отправили тот же external_id с тем же содержимым, придёт 200 и уже созданный заказ — второго не появится. Тот же external_id с другим содержимым — ошибка IDEMPOTENCY_KEY_REUSED: это либо баг, либо новый заказ под старым номером.
Заказ принимается только на блюда активного меню, которые сейчас можно заказать (не скрыты, не в стоп-листе).
Готовая коллекция Postman содержит все запросы этой страницы с включаемыми фильтрами и тестами. Скачать: qreaty-external-api.postman_collection.json.
https://qreaty.com/downloads/qreaty-external-api.postman_collection.json) и нажмите Enter. Появится коллекция «Qreaty — External API».token вставьте токен из раздела «Доступ по API» (как выпустить). base_url уже указывает на https://qreaty.com/api/external/v1; для другого окружения замените его (без слэша в конце). Нажмите Save.sku, option_sku и номер стола в служебные переменные коллекции (они появятся в списке после первого запуска).201 — заказ создан; повторная отправка с тем же external_id (создайте переменную коллекции keep_external_id с любым значением) вернёт 200 и тот же заказ.{primary} Авторизация — Bearer-токен на всю коллекцию, отдельно в запросах её настраивать не нужно. Если в ответах
401— проверьте, что токен вставлен без пробелов и не отозван;403— токену не хватает права для этого запроса.
| Код | Когда | Что делать |
|---|---|---|
401 |
нет токена, он отозван, истёк или это не токен заведения | выпустить новый токен |
403 |
токену не хватает права для этого запроса | выдать право или выпустить другой токен |
404 |
заказа или счёта с таким id в этом заведении нет | проверить id |
422 |
неверное тело: неизвестный SKU или стол, блюдо недоступно сейчас, не выбрана обязательная опция | прочитать errors — у каждой ошибки указан путь, например items.0.sku |
422 + IDEMPOTENCY_KEY_REUSED |
external_id уже использован с другим содержимым |
сменить номер или отправить прежнее содержимое |
429 |
слишком часто | повторить через Retry-After секунд |
Предел — 120 запросов в минуту на токен. Для регулярной сверки меню этого с запасом: берите filter[updated_since] и страницы по 200.
Машиночитаемую спецификацию (OpenAPI) для разработчика интегратора можно запросить в поддержке.