РАЗРАБОТЧИКАМ · API v1
Разработайте приложение для DigiMenu
Подайте заявку на доступ к API и опишите цель использования. После одобрения DigiMenu подключитесь с разрешения ресторана. В руководстве описаны заявка, установка и технические детали.
Как работают приложения
Для каждого приложения нужны заявка и одобрение DigiMenu. Опишите назначение приложения, зачем ему API и какие данные оно будет использовать. До одобрения установка, получение токенов и вебхуки недоступны, в том числе в режиме TEST. Подписка или доступ к кабинету разработчика не заменяют одобрение.
Приложение работает на вашем сервере. Администратор ресторана предоставляет доступ в DigiMenu. Приложение обращается к API с OAuth-токеном этой установки и получает подписанные вебхуки. Загружать код или ZIP-архивы на серверы DigiMenu не нужно.
Базовый адрес API: https://api.digimenu.us/api/v1. Приложения TEST и LIVE используют один адрес. TEST лишь ограничивает установку организацией разработчика; это не отдельная и не имитированная база данных. Используйте отдельный тестовый ресторан.
- Можно читать меню и данные столов, получать заказы и создавать интеграции доставки.
- В API нет методов изменения меню или товаров, создания заказов, управления складом или CRM, приёма платежей и возвратов. Не все возможности собственных приложений DigiMenu доступны сторонним разработчикам.
- Пример работает на Node.js 22.18+ без дополнительных пакетов: подключение OAuth, чтение меню, обновление токенов и получение подписанных вебхуков.
Независимый аккаунт разработчика
Подайте заявку на developers.digimenu.us без аккаунта ресторана и подписки. Подтвердите почту, укажите сведения о себе или компании, цель приложения и нужные данные. После одобрения разработчика можно подать заявку приложения. Каждое приложение проверяется отдельно; одобрение аккаунта само по себе не даёт доступ к API.
В настройках одобренного приложения создайте изолированную тестовую среду. Она не использует таблицы клиентов и поддерживает чтение примерных меню, столов, заказов и изменение статуса доставки заказа. OAuth, курьерские процессы и вебхуки не имитируются. Ключ sandbox_ действует 24 часа и не работает на рабочем адресе /api/v1. Сброс восстанавливает тестовые данные и отменяет старый ключ.
GET https://api.digimenu.us/api/admin/developer-sandbox/v1/menu
Authorization: Bearer SANDBOX_TOKENДля рабочего использования переведите одобренное приложение в LIVE. Администратор ресторана отдельно разрешает доступ через OAuth ниже. Аккаунт разработчика не даёт вход в панель ресторана. При приостановке аккаунта блокируются также его приложения и тестовые ключи.
Регистрация и тестирование
Откройте developers.digimenu.us с одобренным независимым аккаунтом. Разработчики с аккаунтом предприятия могут продолжать использовать panel.digimenu.us/gelistirici при включённом Developer & Platform в организации. Настройки приложения ниже применимы к обоим кабинетам.
- Создайте черновик заявки на доступ к API. Опишите назначение и необходимые данные в 40–2000 символах. Полученный clientId сам по себе не предоставляет доступ.
- Укажите точный HTTPS-адрес перенаправления, например https://app.example/callback. Шаблоны, учётные данные и фрагменты URL не допускаются. Завершающий слеш тоже должен совпадать.
- Для примера выберите menu:read, orders:read и webhooks:manage. Проверяйте предоставленные разрешения в каждом ответе с токенами.
- Сохраните назначение, адреса перенаправления и разрешения, затем отправьте заявку на проверку. После одобрения DigiMenu можно создать необязательный client_secret. Если он настроен, его необходимо передавать при обмене кода и обновлении токенов. Он показывается только один раз.
- После одобрения авторизуйте тестовый ресторан своей организации в режиме TEST. Для callback и вебхуков используйте собственный HTTPS-домен или HTTPS-туннель. HTTP-перенаправления на localhost зарегистрировать нельзя.
APP_ORIGIN=https://eklenti.example
CLIENT_ID=YOUR_CLIENT_ID
SCOPES="menu:read orders:read webhooks:manage"
# Only if a secret was created:
# CLIENT_SECRET=YOUR_CLIENT_SECRET
# Set after registering the webhook receiver:
# WEBHOOK_SECRET=YOUR_WEBHOOK_SECRET
PORT=8787
INBOX_DIR=./webhook-inboxnode --env-file=starter.env digimenu-starter.mjs
# HTTPS proxy/tunnel → http://127.0.0.1:8787
# Open https://eklenti.example/connectПример предназначен для разработки: сессии и токены хранятся в памяти, после перезапуска нужна повторная авторизация. Вебхуки записываются на локальный диск. Перед запуском добавьте вход пользователей, постоянное зашифрованное хранилище токенов, сопоставление организаций и установок, надёжную очередь задач и правила хранения данных. Не добавляйте starter.env в Git.
OAuth и PKCE
PKCE S256 обязателен для всех клиентов. При каждой попытке подключения создавайте новые code_verifier и state и привязывайте их к серверной сессии пользователя. Длина verifier — 43–128 символов. Проверяйте state до обмена кода. Код авторизации одноразовый и действует 60 секунд.
import { randomBytes, createHash } from 'node:crypto';
const verifier = randomBytes(32).toString('base64url');
const state = randomBytes(32).toString('base64url');
const challenge = createHash('sha256').update(verifier).digest('base64url');
// Store verifier + state in this user's server session before redirecting.
const url = new URL('https://panel.digimenu.us/yetkilendir');
url.search = new URLSearchParams({
client_id: process.env.CLIENT_ID,
redirect_uri: 'https://eklenti.example/callback',
scope: 'menu:read orders:read webhooks:manage',
code_challenge: challenge,
code_challenge_method: 'S256',
state,
}).toString();При согласии callback получает code и state; при отказе — error=access_denied и state. Не запрашивайте токен входа в панель управления. Получайте токены приложения через обмен ниже. Тип авторизации client_credentials не поддерживается.
POST https://api.digimenu.us/api/v1/oauth/token
Content-Type: application/json
{
"grant_type": "authorization_code",
"client_id": "YOUR_CLIENT_ID",
"code": "CODE_FROM_CALLBACK",
"redirect_uri": "https://eklenti.example/callback",
"code_verifier": "ORIGINAL_VERIFIER"
}{
"access_token": "ACCESS_TOKEN",
"refresh_token": "REFRESH_TOKEN",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "menu:read orders:read webhooks:manage"
}Обновление токенов и удаление
Токен доступа действует 1 час, токен обновления — 60 дней. Ориентируйтесь на expires_in. При обновлении выдаётся новая пара access_token и refresh_token; сохраняйте их атомарно. Обновляйте токены каждой установки последовательно. Повторное использование старого refresh_token отзывает всё семейство токенов обновления этой установки.
POST https://api.digimenu.us/api/v1/oauth/token
Content-Type: application/json
{
"grant_type": "refresh_token",
"client_id": "YOUR_CLIENT_ID",
"refresh_token": "LATEST_REFRESH_TOKEN"
}Если настроен client_secret, добавляйте его в запрос. Если ответ обновления потерян, не повторяйте запрос со старым токеном вслепую; подключитесь заново через OAuth. Не отправляйте токен циклически после invalid_grant.
Удаление приложения в панели закрывает доступ к API. При APP_REVOKED или APP_NOT_INSTALLED остановите синхронизацию и попросите ресторан повторно авторизовать приложение. SUBSCRIPTION_REQUIRED решается в разделе оплаты ресторана, а не обновлением токена.
Разрешения и доступ к данным
Каждый токен доступа относится к одному ресторану и одной установке. Храните разрешения и токены ресторанов отдельно, с ключами installationId и restaurantId. Разрешения не включают друг друга: orders:write не даёт orders:read.
- menu:read — Активные категории и товары без права изменения меню.
- orders:read — Список и детали заказов; без цен позиций, записей платежей и таблицы клиентов.
- orders:write — Только переходы статуса на этапе доставки; без оплаты, кухни и отмены.
- tables:read — ID, название и номер активного стола; без QR-ключей и данных о занятости.
- deliveries:read / deliveries:write — Чтение и выполнение назначенных курьерских рейсов. Разрешение write создаёт курьера для установки.
- customers:read — Не открывает метод /customers. Подробный адрес заказа доступен только при наличии этого разрешения И назначении заказа курьеру приложения.
- webhooks:manage — Управление получателями и журналами доставки вебхуков приложения. Для получения событий также нужно orders:read или deliveries:read.
Запросы, страницы и повторы
curl 'https://api.digimenu.us/api/v1/orders?channel=DELIVERY&limit=25' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Accept: application/json'Списки заказов и доставок вебхуков по умолчанию используют limit=25, допустимо 1–100. Передавайте nextCursor как cursor следующего запроса; при null остановитесь. /tables и /webhooks возвращают массивы напрямую. /menu возвращает restaurant/categories без обёртки data.
Даты используют ISO 8601. price в меню указан в основных единицах валюты (149.90), deliveryFeeMinor — в минимальных (14990). Валюта в этих ответах отсутствует; определите валюту ресторана отдельно. null может означать отсутствие данных или неприменимость поля.
Idempotency-Key действует только для /orders/{id}/transitions: это отдельный для установки кэш ответов в памяти процесса на пять минут. Используйте разные ключи для каждой комбинации заказа, операции и тела запроса. Кэш не сохраняется после перезапуска и не гарантирует защиту от повторов для всех POST-запросов. После неоднозначного сетевого сбоя проверяйте состояние перед повтором других операций записи.
Настройка и проверка вебхуков
Получатели принадлежат приложению, а не ресторану; не создавайте нового получателя для каждой установки. Нужен публичный HTTPS-адрес на порту 443. Локальные и частные адреса, а также перенаправления отклоняются. Проверяйте подпись исходных байтов запроса до разбора JSON.
POST https://api.digimenu.us/api/v1/webhooks
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json
{
"url": "https://eklenti.example/webhooks",
"events": ["order.created", "order.paid"]
}Ответ 201 показывает secret только один раз. Сохраните его безопасно. Создание получателя не идемпотентно: если ответ потерян, сначала проверьте GET /webhooks. При потере ключа отключите старого получателя и создайте нового.
X-Digimenu-Signature: t=1790467200,v1=<64-character-hex-hmac>
X-Digimenu-Event-Id: <event-uuid>
X-Digimenu-Event-Type: order.created
HMAC-SHA256(secret, timestamp + "." + rawBody){
"id": "00000000-0000-4000-8000-000000000001",
"type": "order.created",
"createdAt": "2026-09-27T00:00:00.000Z",
"restaurantId": "restaurant_example",
"installationId": "installation_example",
"data": { "orderId": "order_example", "channel": "TAKEAWAY" }
}Сравнивайте подписи за постоянное время и отклоняйте метки времени с отклонением более ±300 секунд. id подписанного тела должен совпадать с X-Digimenu-Event-Id. Постоянно храните этот ID для исключения дублей и сверяйте restaurantId/installationId со своими записями установок.
Сначала надёжно сохраните событие, затем верните 2xx в течение 10 секунд. Всего выполняется до 6 попыток доставки, с задержками 30, 120, 600, 1800 и 7200 секунд перед повторами. Работа обработчика может увеличить задержку. В общей сложности 20 записей доставки FAILED автоматически отключают получателя.
Порядок событий и доставка ровно один раз не гарантируются. Получайте текущий статус заказа через GET /orders/{id}. Проверяйте попытки в GET /webhooks/{id}/deliveries. Публичных методов повторной отправки и включения получателя нет.
Список событий
- order.created — Создан заказ на самовывоз или доставку. data: orderId, channel. Нужно orders:read; событие не гарантировано для всех сценариев заказа за столом.
- order.paid — Завершена оплата заказа канала. data: orderId. Нужно orders:read.
- delivery.ready — Заказ назначен внешней курьерской сети. data: orderId, runId и детали доставки. Нужно deliveries:read. Проверяйте назначенный рейс через API; не записывайте конфиденциальные данные доставки в журналы.
- delivery.picked_up / delivery.delivered / delivery.failed — data: orderId, runId, status. Нужно deliveries:read.
- delivery.assigned — Зарезервированное имя, принимаемое при регистрации. В текущей версии это событие не создаётся. Не стройте процесс в ожидании этого события.
Курьерская интеграция
Установите приложение с deliveries:read, deliveries:write и webhooks:manage. Добавьте orders:read для деталей заказа и customers:read для контактных данных назначенного заказа. После назначения доставки рестораном прочитайте рейс по runId из delivery.ready.
GET /api/v1/deliveries/{runId}
POST /api/v1/deliveries/{runId}/depart
POST /api/v1/deliveries/{runId}/pings
{ "lat": 41.01, "lng": 28.97 }
POST /api/v1/deliveries/orders/{orderId}/delivered
{ "code": "CUSTOMER_DELIVERY_CODE" }
# Alternative when delivery fails:
POST /api/v1/deliveries/orders/{orderId}/failed
{ "reason": "CUSTOMER_ABSENT" }Подтверждение доставки проверяет свежие координаты, близость к адресу и выбранный рестораном способ подтверждения. CODE требует код клиента. PHOTO/SIGNATURE требуют запись загрузки, созданную DigiMenu, но в публичной v1 нет метода загрузки подтверждения. Эти режимы нельзя полностью реализовать только через v1.
Курьерским приложениям следует использовать /deliveries. Общий метод /orders/{id}/transitions не проверяет GPS и подтверждение доставки. pings определяет активный рейс по авторизованному курьеру; runId нельзя использовать для выбора другого рейса.
Встроенные экраны
В кабинете разработчика есть embeddedUrl и embeddedOrigin. Экран работает в iframe с sandbox; не рассчитывайте на cookies, доступ к сессии или DOM родительской страницы. Токены не передаются сообщениями iframe. Начните с отдельного HTTPS-приложения.
Мост встроенных экранов ещё не является стабильным контрактом интеграции. Текущие настройки sandbox iframe и обмен сообщениями с указанием origin нужно проверять совместно от начала до конца. Не предполагайте, что придут restaurantId/locale/theme или сообщения автоматической высоты. Перед запуском проверьте этот процесс с поддержкой.
Ошибки и ограничения
Для установки действуют лимиты 30 запросов за 10 секунд и 5000 за часовое окно UTC. Общий лимит на IP — 600 в минуту, для метода токенов — 30 в минуту на IP. После 429 увеличивайте паузу со случайной задержкой. Заголовок Retry-After присутствует не всегда.
{ "code": "insufficient_scope", "requiredScope": "orders:read", "message": "..." }{ "error": "invalid_grant", "error_description": "..." }- 400 — Проверьте типы, допустимые статусы и обязательные поля. Неизвестные поля тела отклоняются. Ошибки проверки также могут иметь формат statusCode/message/error.
- 401 — При APP_UNAUTHENTICATED обновите истёкший токен. APP_REVOKED / APP_NOT_INSTALLED требуют повторной авторизации. Для OAuth invalid_client проверьте client_id и настроенный client_secret.
- 403 — insufficient_scope, SUBSCRIPTION_REQUIRED или ограничение курьера/подтверждения. Повторные запросы не исправляют отсутствие разрешения.
- 404 — Ресурс отсутствует или недоступен ресторану/курьеру этого токена.
- 409 — INVALID_TRANSITION: прочитайте текущий статус заказа перед выбором следующего перехода.
- 429 — rate_limited / quota_exceeded или общий лимит. Замедлите очередь; при исчерпании часовой квоты дождитесь следующего часового окна UTC.
- 5xx или сетевая ошибка — Ограничьте количество повторов чтения. Перед повтором записи проверьте её результат.
Проверка и публикация
Приложение создаётся со статусом DRAFT и режимом TEST. В DRAFT или REJECTED можно менять адреса перенаправления, разрешения и описание. Сохраните хотя бы один адрес и одно разрешение, затем отправьте на проверку IN_REVIEW. После одобрения статус станет APPROVED; затем переведите приложение в LIVE через действие публикации. Для дальнейшего изменения настроек одобренного приложения обратитесь в поддержку.
- Проверьте согласие, отказ, неверный state и истёкший код авторизации.
- Убедитесь, что токены и записи двух тестовых ресторанов не смешиваются.
- Проверьте обновление токенов, потерю ответа и удаление приложения из панели.
- Проверьте вебхуки с изменённым телом, истёкшим временем, дубликатами и нарушенным порядком.
- Ограничьте повторы при 429 и временных ошибках; добавьте обработку повторных операций записи.
- Передайте поддержке назначение приложения, разрешения, шаги тестирования, HTTPS-адреса и контактные данные. Не передавайте секретные ключи и пользовательские токены.
Справочник сверен с текущей реализацией v1 27 сентября 2026 года. Перед использованием новых методов или полей проверьте актуальный OpenAPI. Допускайте неизвестные поля ответа и записывайте неизвестные типы событий, не останавливая приложение.
Справочник методов API
Откройте операцию, чтобы увидеть параметры, тело запроса, поля ответа и статусы HTTP. Описания схем на английском совпадают с OpenAPI. Примеры показывают структуру, а не реальные данные ресторана.
17 / 17 операций
GET/healthСостояние сервиса
Разрешение: Общедоступно
Успешный ответ · 200
{
"status": "ok",
"service": "api-v1",
"ts": "2026-09-27T00:00:00.000Z"
}Все поля и типы ответа
{
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"ok"
]
},
"service": {
"type": "string",
"enum": [
"api-v1"
]
},
"ts": {
"type": "string",
"format": "date-time"
}
},
"required": [
"status",
"service",
"ts"
]
}200 Success
POST/oauth/tokenОбмен кода / обновление токена
Разрешение: Общедоступно
JSON only in these examples. No client_credentials grant. PKCE S256 is mandatory, even for confidential clients. Serialize refresh operations per installation; old refresh-token reuse revokes the refresh family.
Тело запроса · application/json
{
"type": "object",
"properties": {
"grant_type": {
"type": "string",
"enum": [
"authorization_code",
"refresh_token"
]
},
"client_id": {
"type": "string",
"maxLength": 200
},
"client_secret": {
"type": "string",
"description": "Required if a client secret has been configured.",
"maxLength": 200
},
"code": {
"type": "string",
"description": "Required for authorization_code; single use, valid for 60 seconds.",
"maxLength": 200
},
"redirect_uri": {
"type": "string",
"description": "Required for authorization_code. Exact registered URL.",
"maxLength": 500,
"format": "uri"
},
"code_verifier": {
"type": "string",
"description": "Required for authorization_code. Original PKCE verifier.",
"minLength": 43,
"maxLength": 128
},
"refresh_token": {
"type": "string",
"description": "Required for refresh_token grant.",
"maxLength": 200
}
},
"required": [
"grant_type",
"client_id"
]
}Успешный ответ · 200
{
"access_token": "example",
"refresh_token": "example",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "example"
}Все поля и типы ответа
{
"type": "object",
"properties": {
"access_token": {
"type": "string"
},
"refresh_token": {
"type": "string"
},
"token_type": {
"type": "string",
"enum": [
"Bearer"
]
},
"expires_in": {
"type": "integer",
"example": 3600
},
"scope": {
"type": "string",
"description": "Space-separated granted permissions."
}
},
"required": [
"access_token",
"refresh_token",
"token_type",
"expires_in",
"scope"
]
}200 Success400 invalid_request / invalid_grant401 invalid_client403 access_denied: app application requires DigiMenu approval, including TEST mode429 30 requests per minute per IP
GET/meСведения об установке
Разрешение: Действующий токен приложения
Успешный ответ · 200
{
"installationId": "example",
"appId": "example",
"restaurantId": "example",
"scopes": [
"menu:read"
],
"mode": "TEST",
"restaurant": {
"slug": "example",
"name": "example"
}
}Все поля и типы ответа
{
"type": "object",
"properties": {
"installationId": {
"type": "string"
},
"appId": {
"type": "string"
},
"restaurantId": {
"type": "string"
},
"scopes": {
"type": "array",
"items": {
"type": "string",
"enum": [
"menu:read",
"orders:read",
"orders:write",
"tables:read",
"deliveries:read",
"deliveries:write",
"customers:read",
"webhooks:manage"
]
}
},
"mode": {
"type": "string",
"enum": [
"TEST",
"LIVE"
]
},
"restaurant": {
"type": "object",
"properties": {
"slug": {
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"slug",
"name"
],
"nullable": true
}
},
"required": [
"installationId",
"appId",
"restaurantId",
"scopes",
"mode",
"restaurant"
]
}200 Success400 Invalid request or resource state401 Missing/expired token, revoked installation, or app removed403 APP_APPROVAL_REQUIRED (including TEST), missing scope, inactive subscription or delivery restriction404 Resource not found within the installation429 Rate or hourly quota exceeded
GET/menuПолучить меню
Разрешение: menu:read
No pagination. Does not expose recipe cost, inventory, variants or internal preparation data.
Успешный ответ · 200
{
"restaurant": {
"slug": "example",
"name": "example"
},
"categories": [
{
"id": "example",
"name": "example",
"order": 0,
"products": [
{
"id": "example",
"name": "example",
"description": null,
"price": 0,
"isActive": true,
"order": 0,
"allergens": null
}
]
}
]
}Все поля и типы ответа
{
"type": "object",
"properties": {
"restaurant": {
"type": "object",
"properties": {
"slug": {
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"slug",
"name"
]
},
"categories": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"order": {
"type": "integer"
},
"products": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"description": {
"type": "string",
"nullable": true
},
"price": {
"type": "number",
"description": "Major currency units, not minor units. Currency is not included in this response."
},
"isActive": {
"type": "boolean"
},
"order": {
"type": "integer"
},
"allergens": {
"type": "string",
"nullable": true
}
},
"required": [
"id",
"name",
"description",
"price",
"isActive",
"order",
"allergens"
]
}
}
},
"required": [
"id",
"name",
"order",
"products"
]
}
}
},
"required": [
"restaurant",
"categories"
]
}200 Success400 Invalid request or resource state401 Missing/expired token, revoked installation, or app removed403 APP_APPROVAL_REQUIRED (including TEST), missing scope, inactive subscription or delivery restriction404 Resource not found within the installation429 Rate or hourly quota exceeded
GET/tablesСписок столов
Разрешение: tables:read
Returns a bare array. Does not expose QR secrets, sessions or occupancy.
Успешный ответ · 200
[
{
"id": "example",
"name": "example",
"tableNumber": 0
}
]Все поля и типы ответа
{
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"tableNumber": {
"type": "integer"
}
},
"required": [
"id",
"name",
"tableNumber"
]
}
}200 Success400 Invalid request or resource state401 Missing/expired token, revoked installation, or app removed403 APP_APPROVAL_REQUIRED (including TEST), missing scope, inactive subscription or delivery restriction404 Resource not found within the installation429 Rate or hourly quota exceeded
GET/ordersСписок заказов
Разрешение: orders:read
| Параметр | Расположение / тип | Описание |
|---|---|---|
limit | query / integer | Page size. {"type":"integer","minimum":1,"maximum":100,"default":25} |
cursor | query / string | Pass the previous nextCursor unchanged. Stop when null. {"type":"string","maxLength":64} |
channel | query / string | Order channel. {"type":"string","enum":["TABLE","TAKEAWAY","DELIVERY"]} |
status | query / string | Use a known order status, e.g. OUT_FOR_DELIVERY; omit for all statuses. {"type":"string","maxLength":40} |
Успешный ответ · 200
{
"data": [
{
"id": "example",
"shortId": "example",
"channel": "TABLE",
"status": "example",
"createdAt": "2026-09-27T00:00:00.000Z",
"scheduledFor": null,
"deliveryAddress": {},
"deliveryFeeMinor": null,
"items": [
{
"name": "example",
"quantity": 0,
"note": null
}
],
"courierRef": null
}
],
"nextCursor": null
}Все поля и типы ответа
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"shortId": {
"type": "string"
},
"channel": {
"type": "string",
"enum": [
"TABLE",
"TAKEAWAY",
"DELIVERY"
]
},
"status": {
"type": "string"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"scheduledFor": {
"type": "string",
"format": "date-time",
"nullable": true
},
"deliveryAddress": {
"type": "object",
"nullable": true,
"additionalProperties": true,
"description": "Coarse locality with contactRedacted=true by default. Exact address/contact is returned only with customers:read AND assignment to this app’s courier."
},
"deliveryFeeMinor": {
"type": "integer",
"description": "Minor currency units; currency not included.",
"nullable": true
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"quantity": {
"type": "integer"
},
"note": {
"type": "string",
"nullable": true
}
},
"required": [
"name",
"quantity",
"note"
]
}
},
"courierRef": {
"type": "string",
"nullable": true
}
},
"required": [
"id",
"shortId",
"channel",
"status",
"createdAt",
"scheduledFor",
"deliveryAddress",
"deliveryFeeMinor",
"items",
"courierRef"
]
}
},
"nextCursor": {
"type": "string",
"nullable": true
}
},
"required": [
"data",
"nextCursor"
]
}200 Success400 Invalid request or resource state401 Missing/expired token, revoked installation, or app removed403 APP_APPROVAL_REQUIRED (including TEST), missing scope, inactive subscription or delivery restriction404 Resource not found within the installation429 Rate or hourly quota exceeded
GET/orders/{id}Детали заказа
Разрешение: orders:read
| Параметр | Расположение / тип | Описание |
|---|---|---|
id * | path / string | Resource identifier. {"type":"string"} |
Успешный ответ · 200
{
"id": "example",
"shortId": "example",
"channel": "TABLE",
"status": "example",
"createdAt": "2026-09-27T00:00:00.000Z",
"scheduledFor": null,
"deliveryAddress": {},
"deliveryFeeMinor": null,
"items": [
{
"name": "example",
"quantity": 0,
"note": null
}
],
"courierRef": null
}Все поля и типы ответа
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"shortId": {
"type": "string"
},
"channel": {
"type": "string",
"enum": [
"TABLE",
"TAKEAWAY",
"DELIVERY"
]
},
"status": {
"type": "string"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"scheduledFor": {
"type": "string",
"format": "date-time",
"nullable": true
},
"deliveryAddress": {
"type": "object",
"nullable": true,
"additionalProperties": true,
"description": "Coarse locality with contactRedacted=true by default. Exact address/contact is returned only with customers:read AND assignment to this app’s courier."
},
"deliveryFeeMinor": {
"type": "integer",
"description": "Minor currency units; currency not included.",
"nullable": true
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"quantity": {
"type": "integer"
},
"note": {
"type": "string",
"nullable": true
}
},
"required": [
"name",
"quantity",
"note"
]
}
},
"courierRef": {
"type": "string",
"nullable": true
}
},
"required": [
"id",
"shortId",
"channel",
"status",
"createdAt",
"scheduledFor",
"deliveryAddress",
"deliveryFeeMinor",
"items",
"courierRef"
]
}200 Success400 Invalid request or resource state401 Missing/expired token, revoked installation, or app removed403 APP_APPROVAL_REQUIRED (including TEST), missing scope, inactive subscription or delivery restriction404 Resource not found within the installation429 Rate or hourly quota exceeded
POST/orders/{id}/transitionsИзменить этап доставки
Разрешение: orders:write
ASSIGNED_TO_COURIER → OUT_FOR_DELIVERY → DELIVERED or DELIVERY_FAILED. Same status is a no-op. This generic route does not run courier GPS/proof checks: courier apps should use /deliveries. No payment, kitchen, cancel, create-order or refund operation is exposed.
| Параметр | Расположение / тип | Описание |
|---|---|---|
id * | path / string | Resource identifier. {"type":"string"} |
Idempotency-Key | header / string | Optional. Unique per installation AND operation. A response is cached for 5 minutes in one process; not durable across restarts. Never reuse for another order or body. {"type":"string"} |
Тело запроса · application/json
{
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"OUT_FOR_DELIVERY",
"DELIVERED",
"DELIVERY_FAILED"
]
}
},
"required": [
"status"
]
}Успешный ответ · 201
{
"id": "example",
"shortId": "example",
"channel": "TABLE",
"status": "example",
"createdAt": "2026-09-27T00:00:00.000Z",
"scheduledFor": null,
"deliveryAddress": {},
"deliveryFeeMinor": null,
"items": [
{
"name": "example",
"quantity": 0,
"note": null
}
],
"courierRef": null
}Все поля и типы ответа
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"shortId": {
"type": "string"
},
"channel": {
"type": "string",
"enum": [
"TABLE",
"TAKEAWAY",
"DELIVERY"
]
},
"status": {
"type": "string"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"scheduledFor": {
"type": "string",
"format": "date-time",
"nullable": true
},
"deliveryAddress": {
"type": "object",
"nullable": true,
"additionalProperties": true,
"description": "Coarse locality with contactRedacted=true by default. Exact address/contact is returned only with customers:read AND assignment to this app’s courier."
},
"deliveryFeeMinor": {
"type": "integer",
"description": "Minor currency units; currency not included.",
"nullable": true
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"quantity": {
"type": "integer"
},
"note": {
"type": "string",
"nullable": true
}
},
"required": [
"name",
"quantity",
"note"
]
}
},
"courierRef": {
"type": "string",
"nullable": true
}
},
"required": [
"id",
"shortId",
"channel",
"status",
"createdAt",
"scheduledFor",
"deliveryAddress",
"deliveryFeeMinor",
"items",
"courierRef"
]
}201 Success400 Invalid request or resource state401 Missing/expired token, revoked installation, or app removed403 APP_APPROVAL_REQUIRED (including TEST), missing scope, inactive subscription or delivery restriction404 Resource not found within the installation409 INVALID_TRANSITION429 Rate or hourly quota exceeded
GET/webhooksСписок получателей вебхуков
Разрешение: webhooks:manage
App-wide, not restaurant-specific. Register once per app, not once per installation.
Успешный ответ · 200
[
{
"id": "example",
"url": "https://eklenti.example/webhooks",
"events": [
"order.created"
],
"active": true,
"disabledAt": null,
"createdAt": "2026-09-27T00:00:00.000Z"
}
]Все поля и типы ответа
{
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"url": {
"type": "string",
"format": "uri"
},
"events": {
"type": "array",
"items": {
"type": "string",
"enum": [
"order.created",
"order.paid",
"delivery.ready",
"delivery.assigned",
"delivery.picked_up",
"delivery.delivered",
"delivery.failed"
]
}
},
"active": {
"type": "boolean"
},
"disabledAt": {
"type": "string",
"format": "date-time",
"nullable": true
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"id",
"url",
"events",
"active",
"disabledAt",
"createdAt"
]
}
}200 Success400 Invalid request or resource state401 Missing/expired token, revoked installation, or app removed403 APP_APPROVAL_REQUIRED (including TEST), missing scope, inactive subscription or delivery restriction404 Resource not found within the installation429 Rate or hourly quota exceeded
POST/webhooksСоздать получателя вебхуков
Разрешение: webhooks:manage
No idempotency-key support. Check GET /webhooks before retrying a create after a network timeout; a duplicate request creates another endpoint. Secret is returned once.
Тело запроса · application/json
{
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "Public HTTPS URL on port 443; credentials, redirects and private hosts are rejected.",
"format": "uri",
"maxLength": 2048
},
"events": {
"type": "array",
"items": {
"type": "string",
"enum": [
"order.created",
"order.paid",
"delivery.ready",
"delivery.assigned",
"delivery.picked_up",
"delivery.delivered",
"delivery.failed"
],
"maxLength": 64
},
"minItems": 1
}
},
"required": [
"url",
"events"
]
}Успешный ответ · 201
{
"id": "example",
"url": "https://eklenti.example/webhooks",
"events": [
"order.created"
],
"active": true,
"disabledAt": null,
"createdAt": "2026-09-27T00:00:00.000Z",
"secret": "example"
}Все поля и типы ответа
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"url": {
"type": "string",
"format": "uri"
},
"events": {
"type": "array",
"items": {
"type": "string",
"enum": [
"order.created",
"order.paid",
"delivery.ready",
"delivery.assigned",
"delivery.picked_up",
"delivery.delivered",
"delivery.failed"
]
}
},
"active": {
"type": "boolean"
},
"disabledAt": {
"type": "string",
"format": "date-time",
"nullable": true
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"secret": {
"type": "string",
"description": "Signing secret; returned once at creation."
}
},
"required": [
"id",
"url",
"events",
"active",
"disabledAt",
"createdAt",
"secret"
]
}201 Success400 Invalid request or resource state401 Missing/expired token, revoked installation, or app removed403 APP_APPROVAL_REQUIRED (including TEST), missing scope, inactive subscription or delivery restriction404 Resource not found within the installation429 Rate or hourly quota exceeded
DELETE/webhooks/{id}Отключить получателя вебхуков
Разрешение: webhooks:manage
Soft disable; repeating for your already-disabled endpoint succeeds. No public re-enable endpoint: register a new endpoint and store its new secret.
| Параметр | Расположение / тип | Описание |
|---|---|---|
id * | path / string | Resource identifier. {"type":"string"} |
Успешный ответ · 200
{
"id": "example",
"active": false
}Все поля и типы ответа
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"active": {
"type": "boolean",
"enum": [
false
]
}
},
"required": [
"id",
"active"
]
}200 Success400 Invalid request or resource state401 Missing/expired token, revoked installation, or app removed403 APP_APPROVAL_REQUIRED (including TEST), missing scope, inactive subscription or delivery restriction404 Resource not found within the installation429 Rate or hourly quota exceeded
GET/webhooks/{id}/deliveriesЖурнал доставки вебхуков
Разрешение: webhooks:manage
| Параметр | Расположение / тип | Описание |
|---|---|---|
id * | path / string | Resource identifier. {"type":"string"} |
limit | query / integer | Page size. {"type":"integer","minimum":1,"maximum":100,"default":25} |
cursor | query / string | Pass the previous nextCursor unchanged. Stop when null. {"type":"string","maxLength":64} |
Успешный ответ · 200
{
"data": [
{
"id": "example",
"eventType": "example",
"status": "PENDING",
"attempts": 0,
"responseCode": null,
"lastError": null,
"createdAt": "2026-09-27T00:00:00.000Z"
}
],
"nextCursor": null
}Все поля и типы ответа
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"eventType": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"PENDING",
"DELIVERED",
"FAILED"
]
},
"attempts": {
"type": "integer"
},
"responseCode": {
"type": "integer",
"nullable": true
},
"lastError": {
"type": "string",
"nullable": true
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"id",
"eventType",
"status",
"attempts",
"responseCode",
"lastError",
"createdAt"
]
}
},
"nextCursor": {
"type": "string",
"nullable": true
}
},
"required": [
"data",
"nextCursor"
]
}200 Success400 Invalid request or resource state401 Missing/expired token, revoked installation, or app removed403 APP_APPROVAL_REQUIRED (including TEST), missing scope, inactive subscription or delivery restriction404 Resource not found within the installation429 Rate or hourly quota exceeded
GET/deliveries/{runId}Курьерский рейс
Разрешение: deliveries:read
Requires a courier installation created by granting deliveries:write. Reads only that installation’s courier runs.
| Параметр | Расположение / тип | Описание |
|---|---|---|
runId * | path / string | Resource identifier. {"type":"string"} |
Успешный ответ · 200
{
"id": "example",
"status": "example",
"startedAt": null,
"completedAt": null,
"routeDistanceMeters": null,
"routeDurationSeconds": null,
"orders": [
{
"id": "example",
"status": "example"
}
],
"location": {
"lat": 0,
"lng": 0,
"at": "2026-09-27T00:00:00.000Z"
}
}Все поля и типы ответа
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"status": {
"type": "string"
},
"startedAt": {
"type": "string",
"format": "date-time",
"nullable": true
},
"completedAt": {
"type": "string",
"format": "date-time",
"nullable": true
},
"routeDistanceMeters": {
"type": "integer",
"nullable": true
},
"routeDurationSeconds": {
"type": "integer",
"nullable": true
},
"orders": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"status": {
"type": "string"
}
},
"required": [
"id",
"status"
]
}
},
"location": {
"type": "object",
"properties": {
"lat": {
"type": "number"
},
"lng": {
"type": "number"
},
"at": {
"type": "string",
"format": "date-time"
}
},
"required": [
"lat",
"lng",
"at"
],
"nullable": true
}
},
"required": [
"id",
"status",
"startedAt",
"completedAt",
"routeDistanceMeters",
"routeDurationSeconds",
"orders",
"location"
]
}200 Success400 Invalid request or resource state401 Missing/expired token, revoked installation, or app removed403 APP_APPROVAL_REQUIRED (including TEST), missing scope, inactive subscription or delivery restriction404 Resource not found within the installation429 Rate or hourly quota exceeded
POST/deliveries/{runId}/departНачать рейс
Разрешение: deliveries:write
ASSIGNED → ON_ROUTE. Moves assigned orders to OUT_FOR_DELIVERY. A second depart fails with INVALID_RUN_STATE; reconcile GET before retrying.
| Параметр | Расположение / тип | Описание |
|---|---|---|
runId * | path / string | Resource identifier. {"type":"string"} |
Успешный ответ · 201
{
"ok": true,
"orders": 0
}Все поля и типы ответа
{
"type": "object",
"properties": {
"ok": {
"type": "boolean"
},
"orders": {
"type": "integer"
}
},
"required": [
"ok",
"orders"
]
}201 Success400 Invalid request or resource state401 Missing/expired token, revoked installation, or app removed403 APP_APPROVAL_REQUIRED (including TEST), missing scope, inactive subscription or delivery restriction404 Resource not found within the installation429 Rate or hourly quota exceeded
POST/deliveries/{runId}/pingsПередать координаты
Разрешение: deliveries:write
The implementation resolves the active run from the authenticated courier and does not use runId to select a run. Send your assigned active run ID. Pings may be dropped with stored=false / THROTTLED; do not immediately retry.
| Параметр | Расположение / тип | Описание |
|---|---|---|
runId * | path / string | Resource identifier. {"type":"string"} |
Тело запроса · application/json
{
"type": "object",
"properties": {
"lat": {
"type": "number",
"minimum": -90,
"maximum": 90
},
"lng": {
"type": "number",
"minimum": -180,
"maximum": 180
},
"accuracyM": {
"type": "number"
},
"headingDeg": {
"type": "number"
},
"speedMps": {
"type": "number"
},
"recordedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"lat",
"lng"
]
}Успешный ответ · 201
{
"stored": true,
"requeried": true
}Все поля и типы ответа
{
"oneOf": [
{
"type": "object",
"properties": {
"stored": {
"type": "boolean",
"enum": [
true
]
},
"requeried": {
"type": "boolean"
}
},
"required": [
"stored",
"requeried"
]
},
{
"type": "object",
"properties": {
"stored": {
"type": "boolean",
"enum": [
false
]
},
"reason": {
"type": "string",
"enum": [
"THROTTLED"
]
}
},
"required": [
"stored",
"reason"
]
}
]
}201 Success400 Invalid request or resource state401 Missing/expired token, revoked installation, or app removed403 APP_APPROVAL_REQUIRED (including TEST), missing scope, inactive subscription or delivery restriction404 Resource not found within the installation429 Rate or hourly quota exceeded
POST/deliveries/orders/{orderId}/deliveredПодтвердить доставку
Разрешение: deliveries:write
Requires assigned order OUT_FOR_DELIVERY, fresh GPS near drop-off, and restaurant-selected proof. CODE requires code; PHOTO/SIGNATURE require a platform-issued upload unavailable through public v1. Do not treat these modes as a complete external-only integration.
| Параметр | Расположение / тип | Описание |
|---|---|---|
orderId * | path / string | Resource identifier. {"type":"string"} |
Тело запроса · application/json
{
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "Required when the restaurant uses CODE proof mode.",
"maxLength": 16
},
"proofRef": {
"type": "string",
"description": "PHOTO/SIGNATURE require a platform-issued upload. The public v1 API has no proof-upload endpoint; do not submit an arbitrary URL.",
"maxLength": 500
}
},
"required": []
}Успешный ответ · 201
{
"ok": true
}Все поля и типы ответа
{
"type": "object",
"properties": {
"ok": {
"type": "boolean"
}
},
"required": [
"ok"
]
}201 Success400 Invalid request or resource state401 Missing/expired token, revoked installation, or app removed403 APP_APPROVAL_REQUIRED (including TEST), missing scope, inactive subscription or delivery restriction404 Resource not found within the installation429 Rate or hourly quota exceeded
POST/deliveries/orders/{orderId}/failedСообщить о неудачной доставке
Разрешение: deliveries:write
Requires an assigned OUT_FOR_DELIVERY order. No general idempotency header support; reconcile order state after an ambiguous response.
| Параметр | Расположение / тип | Описание |
|---|---|---|
orderId * | path / string | Resource identifier. {"type":"string"} |
Тело запроса · application/json
{
"type": "object",
"properties": {
"reason": {
"type": "string",
"enum": [
"CUSTOMER_ABSENT",
"WRONG_ADDRESS",
"CUSTOMER_REJECTED",
"OTHER"
]
},
"note": {
"type": "string",
"description": "Accepted by validation; currently not persisted by the delivery service.",
"maxLength": 200
}
},
"required": [
"reason"
]
}Успешный ответ · 201
{
"ok": true
}Все поля и типы ответа
{
"type": "object",
"properties": {
"ok": {
"type": "boolean"
}
},
"required": [
"ok"
]
}201 Success400 Invalid request or resource state401 Missing/expired token, revoked installation, or app removed403 APP_APPROVAL_REQUIRED (including TEST), missing scope, inactive subscription or delivery restriction404 Resource not found within the installation429 Rate or hourly quota exceeded
Поддержка интеграций
Укажите ID приложения, метод API и код ошибки. Не отправляйте токены и секретные ключи.
support@digimenu.us