Документация для разработчиков

TapTime REST API

Читайте и обновляйте бронирования столиков и записи, получайте заказы и карты лояльности, опрашивайте упорядоченную ленту событий и принимайте подписанные веб-хуки — из своей CRM, POS-системы, хранилища данных или платформы автоматизации. На этой странице — полный справочник; зачем всё это нужно, объясняет руководство по отслеживанию конверсий.

Базовый URLhttps://api.tapti.me AuthBearer token ФорматJSON Зачем это нужно

Для каждого запроса требуется API-ключ компании (раздел «Интеграции» → «Вебхуки и API» в панели управления), который необходимо отправить в поле «Authorization: Bearer tt_live_….». Ответы и ошибки передаются в формате JSON.

Изменения в подтвержденных бронированиях, внесенные после определенной даты
curl "https://api.tapti.me/v1/company/reservations?status=confirmed&updatedSince=2026-09-01T00:00:00Z" \
  -H "Authorization: Bearer tt_live_…"

Аутентификация

Каждый запрос содержит API-ключ компании в качестве токена «bearer». Создайте его в панели управления — «Интеграции» → «Вебхуки и API» → «Ключи REST API» — где он отображается однократно и хранится на стороне сервера исключительно в виде хеша SHA-256; утерянный ключ аннулируется и заменяется, но не восстанавливается. Компания может иметь до 10 активных ключей.

  • Ключи только для чтения могут вызывать любую конечную точку GET, а также подписывать и отписывать веб-хуки — подписка не передаёт ничего, что ключ не мог бы прочитать и так.
  • Ключи для чтения и записи также могут менять статус бронирования запросом POST; ключ только для чтения получает на этих маршрутах ответ 403 Forbidden.
  • Ключ принадлежит одной компании — все списки и запросы уже ограничены ею, параметра companyId нет.

Ограничения по скорости

50 запросов в минуту на ключ в скользящем окне — общий лимит для всех конечных точек. При превышении возвращается 429 Too Many Requests; сделайте паузу и повторите запрос, а не опрашивайте чаще — или подпишите веб-хук и перестаньте опрашивать вовсе.

Конечные точки

GET /v1/company Только для чтения или для чтения и записи

Получить текущую компанию

Компания, которой принадлежит ключ, и какие возможности предоставляет сам ключ.

GET /v1/company/reservations Только для чтения или для чтения и записи

Список бронирований

Бронирования столиков для компании, в порядке убывания даты начала — или, если установлено значение updatedSince, в порядке убывания даты последнего обновления.

ПараметрTypeЗначение
status string Разделены запятыми: «в ожидании», «подтверждено», «присутствовал», «завершено», «не явился», «отменено». Статус «отменено» соответствует обеим причинам отмены.
branchId integer Ограничить до одной ветви.
from ISO 8601 datetime Только бронирования, начинающиеся в это время или позже (по UTC, если смещение не указано).
to ISO 8601 datetime Только бронирования, начинающиеся до этого времени.
updatedSince ISO 8601 datetime Только бронирования, измененные с этого момента; переключает сортировку на updatedAt по возрастанию для синхронизации.
limit integer Размер страницы: от 1 до 100. По умолчанию — 50.
page integer Нумерация страниц, начинающаяся с 1. По умолчанию — 1.
GET /v1/company/appointments Только для чтения или для чтения и записи

Список встреч

Такой же формат и фильтры, как и в модуле «Бронирования», для модуля «Встречи».

ПараметрTypeЗначение
status string Разделены запятыми: в ожидании, подтверждено, завершено, не явился, отменено.
branchId integer Ограничить до одной ветви.
from ISO 8601 datetime Только бронирования, начинающиеся в это время или позже.
to ISO 8601 datetime Только бронирования, начинающиеся до этого времени.
updatedSince ISO 8601 datetime Только бронирования, измененные с этого момента; сортировка по updatedAt в порядке возрастания.
limit integer Размер страницы: от 1 до 100. По умолчанию — 50.
page integer Нумерация страниц, начинающаяся с 1. По умолчанию — 1.
GET /v1/company/reservations/{id} Только для чтения или для чтения и записи

Забронировать номер

Одно ограничение: данные передаются в том же формате, в котором они поступают через веб-хуки, с указанием источника. Возвращается код 404, если идентификатор не принадлежит компании, указанной в ключе.

GET /v1/company/appointments/{id} Только для чтения или для чтения и записи

Записаться на прием

Одно назначение, формат и правила такие же, как при поиске бронирования.

POST /v1/company/reservations/{id}/status Только для чтения и записи

Изменить статус бронирования

Подтвердить, закрепить за столом, завершить, отметить как «не явился», отменить или возобновить — вызывает те же веб-хуки и конверсии, что и при изменении статуса на доске. Тело JSON: {"status": "..."}.

ПараметрTypeЗначение
status string, required Один из следующих вариантов: «в ожидании», «подтверждено», «зарегистрирован», «завершено», «не явился», «отменено» (также допускаются варианты «canceled» и «canceled_by_venue»).
POST /v1/company/appointments/{id}/status Только для чтения и записи

Изменить статус встречи

То же самое, что и конечная точка бронирования, но без состояния «занято».

ПараметрTypeЗначение
status string, required Одно из следующих: «в процессе», «подтверждено», «завершено», «не явился», «отменено» (также допускаются варианты «canceled» и «canceled_by_venue»).
GET /v1/company/events Только для чтения или для чтения и записи

Обработать поток событий

Все события бронирований, заказов и лояльности, начиная с самых старых, — та же лента, из которой формируются веб-хуки. Передайте последний полученный курсор в after, чтобы получить только новое, и type — чтобы получать только некоторые виды событий.

ПараметрTypeЗначение
after integer cursor Курсор после последнего обработанного события. Если не указано, то начнется с самого начала.
type string Типы или семейства событий через запятую: booking.confirmed,order.placed или order, loyalty.*. Не указывайте, чтобы получать все события.
limit integer Размер страницы: от 1 до 100. По умолчанию — 50.
GET /v1/company/orders Только для чтения или для чтения и записи

Список заказов

Заказы гостей за столом, навынос и с доставкой, а также все продажи, пробитые на кассе, начиная с самых старых — или, если задан paidSince, в порядке оплаты. Заказ, который ещё ждёт предоплаты, не выводится.

ПараметрTypeЗначение
status string Через запятую: open, paid.
source string customer (оформлен гостем) или staff (пробит персоналом).
fulfilment string Через запятую: dine_in, takeaway, delivery.
branchId integer Только один филиал.
from ISO 8601 datetime Только заказы, созданные в это время или позже.
to ISO 8601 datetime Только заказы, созданные до этого времени.
paidSince ISO 8601 datetime Только заказы, оплаченные с этого момента; сортировка по paidAt по возрастанию — для синхронизации продаж.
limit integer Размер страницы: от 1 до 100. По умолчанию — 50.
page integer Нумерация страниц, начинающаяся с 1. По умолчанию — 1.
GET /v1/company/orders/{id} Только для чтения или для чтения и записи

Получить заказ

Один заказ с позициями, суммами и атрибуцией — в том же формате, что и в веб-хуках заказов.

GET /v1/company/loyalty/programs Только для чтения или для чтения и записи

Список программ лояльности

Все программы со штампами: название, статус, сколько штампов нужно, награда и где она действует.

GET /v1/company/loyalty/cards Только для чтения или для чтения и записи

Список карт лояльности

Карты участников в формате объекта лояльности. Когда участник заполняет карту, она получает статус completed, а рядом появляется новая активная; customer.id — это участник.

ПараметрTypeЗначение
programId integer Только одна программа.
customerId integer Только один участник.
status string Через запятую: active, completed.
updatedSince ISO 8601 datetime Только карты, получившие штамп или заполненные с этого момента; сортировка по updatedAt по возрастанию.
limit integer Размер страницы: от 1 до 100. По умолчанию — 50.
page integer Нумерация страниц, начинающаяся с 1. По умолчанию — 1.
GET /v1/company/loyalty/rewards Только для чтения или для чтения и записи

Список наград лояльности

Награды, полученные за заполненную карту, — с кодом, сроком действия и отметкой, использованы ли они.

ПараметрTypeЗначение
programId integer Только одна программа.
customerId integer Только один участник.
status string Через запятую: issued, redeemed, expired.
from ISO 8601 datetime Только награды, выданные в это время или позже.
to ISO 8601 datetime Только награды, выданные до этого времени.
limit integer Размер страницы: от 1 до 100. По умолчанию — 50.
page integer Нумерация страниц, начинающаяся с 1. По умолчанию — 1.
GET /v1/company/webhooks Только для чтения или для чтения и записи

Список подписок на веб-хуки

Подписки, созданные этим ключом. Веб-хуки, добавленные в панели, здесь не показываются.

POST /v1/company/webhooks Только для чтения или для чтения и записи

Подписать веб-хук

Начинает отправлять события на URL — этот вызов делает приложение платформы автоматизации, когда пользователь включает триггер. Возвращает подписку и её секрет подписи — один раз. Тело JSON: {"url": "…", "events": ["order.placed"]}; формат Zapier {"target_url": "…", "event": "…"} тоже принимается.

ПараметрTypeЗначение
url string, required Адрес https, на который отправлять события (также принимается target_url).
events array of strings, required Типы событий, семейства вроде order.* или loyalty либо * для всех событий (для одного типа также принимается event).
description string Название, которое показывается в панели. По умолчанию — платформа и имя ключа.
DELETE /v1/company/webhooks/{id} Только для чтения или для чтения и записи

Отписать веб-хук

Прекращает отправку по подписке, созданной этим ключом. Возвращает 204. При отзыве ключа удаляются и все его подписки.

Объект бронирования

Бронирование и запись на прием представлены в виде одного общего шаблона: тип, идентификатор, статус, источник, guestInitiated, startsAt/endsAt/часовой пояс (пояс филиала), валюта, компания, филиал, гость, атрибуция, conversionId, createdAt/updatedAt — плюс partySize и таблица для бронирования, услуга и специалист для записи на приём. Это именно то, что передаёт веб-хук, поэтому получатель, обрабатывающий одно из них, обрабатывает и другое.

GET /v1/company/reservations/4821 → данные
{
  "data": {
    "kind": "reservation",
    "id": 4821,
    "status": "confirmed",
    "source": "online",
    "guestInitiated": true,
    "startsAt": "2026-09-12T20:00:00+03:00",
    "endsAt": "2026-09-12T21:30:00+03:00",
    "timezone": "Asia/Baku",
    "currency": "AZN",
    "company": { "id": 12, "name": "Cafe Aroma", "slug": "cafe-aroma", "country": "AZ" },
    "branch": { "id": 3, "name": "Nizami st." },
    "partySize": 4,
    "table": { "id": 9, "label": "T3" },
    "guest": { "name": "Maria K.", "phone": "…", "email": "…" },
    "locale": "en",
    "note": null,
    "conversionId": "tt3f9c…",
    "createdAt": "2026-09-10T08:12:04+00:00",
    "updatedAt": "2026-09-12T20:00:03+00:00",
    "attribution": { "channel": "widget", "utmSource": "instagram", "gclid": null, "fbclid": "IwAR2…" }
  }
}

Объект заказа

Заказ выглядит одинаково везде — в REST API, в веб-хуках заказов и в ленте событий: kind ("order"), id, number (номер, который называет персонал), status (open или paid), source (customer или staff), guestInitiated, fulfilment, table, label, deliveryAddress, note, currency, timezone, company, branch, customer (участник программы лояльности, если персонал его указал), items (name, variant, quantity, unitPriceCents, subtotalCents), itemCount, subtotalCents, discountCents, deliveryFeeCents, tipCents, totalCents, valueCents (стоимость заказа без чаевых — именно эту сумму передают конверсии), paymentMethod, servedBy, conversionId, createdAt, paidAt и attribution. Суммы всегда указаны в минимальных единицах валюты.

GET /v1/company/orders/9170 → данные
{
  "data": {
    "kind": "order",
    "id": 9170,
    "number": 42,
    "status": "paid",
    "source": "customer",
    "guestInitiated": true,
    "fulfilment": "takeaway",
    "table": null,
    "label": "Ana",
    "currency": "EUR",
    "branch": { "id": 3, "name": "Vitosha Blvd" },
    "customer": { "id": 311, "name": "Ana", "phone": "…" },
    "items": [
      { "menuItemId": 88, "name": "Flat white", "variant": "Large",
        "quantity": 2, "unitPriceCents": 450, "subtotalCents": 900 }
    ],
    "itemCount": 2,
    "subtotalCents": 900,
    "discountCents": 0,
    "deliveryFeeCents": 0,
    "tipCents": 100,
    "totalCents": 1000,
    "valueCents": 900,
    "paymentMethod": "online",
    "conversionId": "tt81ad…",
    "createdAt": "2026-09-12T12:04:10+03:00",
    "paidAt": "2026-09-12T12:05:02+03:00",
    "attribution": { "channel": "web", "utmSource": "google", "gclid": "Cj0K…" }
  }
}

Объект лояльности

Все события, карты и награды лояльности имеют один формат: kind ("loyalty"), id (карта), timezone, company, branch (где это произошло, если применимо), program (id, name, stampsRequired, rewardTitle), customer (id, name, phone, locale), card (id, status, stampsCount, stampsRequired, stampsToReward, createdAt), stamp (для штампа: source, issuedBy, createdAt) и reward (для награды: code, title, status, expiresAt, redeemedAt, redeemedBy), а также conversionId — идентификатор, под которым передаётся регистрация в программе лояльности.

GET /v1/company/loyalty/cards → data[0]
{
  "kind": "loyalty",
  "id": 5120,
  "program": { "id": 4, "name": "Coffee card", "stampsRequired": 8, "rewardTitle": "Free coffee" },
  "customer": { "id": 311, "name": "Ana", "phone": "…", "locale": "bg" },
  "card": { "id": 5120, "status": "active", "stampsCount": 5,
            "stampsRequired": 8, "stampsToReward": 3 },
  "branch": { "id": 3, "name": "Vitosha Blvd" },
  "stamp": { "source": "qr_scan", "issuedBy": "Ivan", "createdAt": "…" },
  "reward": null,
  "conversionId": "tt5c02…"
}

Лента событий

Каждая строка имеет вид { id, cursor, type, createdAt, previousStatus, data }. В data лежит объект под ключом, который задаёт префикс события: data.booking, data.order или data.loyalty. Сохраняйте наибольший обработанный курсор и передавайте его обратно в after — строки никогда не пропускаются и не повторяются, поэтому после сбоя можно спокойно продолжить. Игнорируйте типы, которые вы не обрабатываете: могут появиться новые.

Тип событияЗначение
booking.requestedГость запросил бронирование, которое ждёт вашего подтверждения.
booking.confirmedБронирование подтверждено — сразу при создании или позже персоналом.
booking.cancelledОтменено гостем или заведением; кем именно — видно в status.
booking.no_showГость не пришёл.
booking.completedВизит завершён.
order.placedЗаказ гостя поступил в заведение — со страницы, по QR-коду стола, навынос или с доставкой; если заведение берёт предоплату — после оплаты.
order.paidОплачен любой заказ, включая продажи, пробитые на кассе.
loyalty.member_joinedКлиент получил свой первый штамп в программе.
loyalty.stamp_addedНа карту добавлен штамп.
loyalty.reward_issuedКарта заполнена, награда начислена.
loyalty.reward_redeemedНаграда выдана гостю.
Будьте в курсе событий с помощью ленты новостей
curl "https://api.tapti.me/v1/company/events?after=998&limit=100" \
  -H "Authorization: Bearer tt_live_…"

Веб-хуки

Создайте конечную точку в разделе «Интеграции» → «Вебхуки и API» — или подключите Zapier, Make, n8n или Pipedream в разделе «Интеграции» → «Автоматизация», — и TapTime будет отправлять подписанное событие в формате JSON методом POST в момент, когда меняется бронирование, заказ или карта лояльности. События выбираются отдельно для каждой конечной точки. У компании может быть до 50 веб-хуков, постбэков, чатов и подключений автоматизации в сумме.

ЗаголовокЗначение
TapTime-EventТип события, например booking.confirmed.
TapTime-Event-IdУникальный идентификатор события — используйте его для удаления дубликатов при повторной попытке доставки.
TapTime-DeliveryИдентификатор данной конкретной попытки доставки.
TapTime-Signaturet = <время по системе Unix>, v1 = <шестнадцатеричное значение HMAC-SHA256 выражения «t.rawBody»>, подписанное собственным секретным ключом конечной точки.
  • Любой ответ с кодом 2xx считается доставленным; в случае ответа, отличного от 2xx, или истечения времени ожидания повторная попытка осуществляется с интервалом отсрочки (1 мин, 5 мин, 15 мин, 1 ч, 3 ч, 6 ч, 12 ч) до 8 попыток — при получении кода 410 повторные попытки прекращаются.
  • Перенаправления не обрабатываются.
  • В производственной среде URL-адрес должен использовать протокол HTTPS и не должен указывать на частный или петлевой адрес.
  • Доставка осуществляется как минимум один раз: всегда проверяйте подпись и удаляйте дубликаты по TapTime-Event-Id.
ПОСТ · application/json · booking.confirmed
{
  "id": "evt_9f3c2a7e1b",
  "type": "booking.confirmed",
  "createdAt": "2026-09-12T19:02:11+03:00",
  "test": false,
  "data": { "booking": { "kind": "reservation", "id": 4821, "status": "confirmed", "…": "…" } }
}
Проверка подписи (Node.js)
const [t, v1] = req.headers["taptime-signature"]
  .split(",").map(part => part.split("=")[1]);
const expected = crypto
  .createHmac("sha256", process.env.TAPTIME_WEBHOOK_SECRET)
  .update(`${t}.${rawBody}`)
  .digest("hex");
const valid = crypto.timingSafeEqual(
  Buffer.from(expected), Buffer.from(v1));

Подписки на веб-хуки

Платформы автоматизации включают и выключают триггеры через API, а не просят пользователя вставить URL («REST hooks»): отправьте POST с собственным URL платформы и нужными событиями, сохраните возвращённый id и удалите подписку запросом DELETE, когда триггер выключат. Подписка — обычный подписанный веб-хук: она видна в панели с отметкой ключа, который её создал.

  • Ключ видит и удаляет только созданные им подписки; при отзыве ключа удаляются все они.
  • Адреса на hooks.zapier.com, make.com и pipedream.net распознаются и показываются с названием платформы; любой другой адрес https — обычный веб-хук.
  • Секрет подписи возвращается один раз — в ответе на POST; владелец может снова посмотреть его в панели.
Подписать URL на новые заказы
curl -X POST "https://api.tapti.me/v1/company/webhooks" \
  -H "Authorization: Bearer tt_live_…" -H "Content-Type: application/json" \
  -d '{"url": "https://hooks.zapier.com/hooks/catch/123/abc/", "events": ["order.placed"]}'

Отправка данных

GET- или POST-запрос на собственный URL вашего трекера с заполненными макросами — для платформ, которые принимают постбэки в строке запроса, а не JSON-вебхуки. Для заказа {value} — сумма заказа без чаевых, а {order_id} — его идентификатор.

URL-адрес для отправки данных с заполнителями · GET или POST
https://tracker.example/postback
  ?cid={click_id}&event={event}&status={status}
  &payout={value}&cur={currency}

Доступные заполнители

  • {event}
  • {event_id}
  • {status}
  • {booking_id}
  • {booking_type}
  • {order_id}
  • {customer_id}
  • {conversion_id}
  • {value}
  • {currency}
  • {party_size}
  • {branch_id}
  • {timestamp}
  • {utm_source}
  • {utm_medium}
  • {utm_campaign}
  • {utm_term}
  • {utm_content}
  • {gclid}
  • {fbclid}
  • {msclkid}
  • {ttclid}
  • {click_id}

Ошибки

Каждая ошибка имеет формат JSON: { "error": "<code>", "message": "<human-readable>" }.

StatusошибкаЗначение
401 unauthorized Отсутствует заголовок «Authorization», либо ключ недействителен или его действие отозвано.
403 forbidden Ключ, доступный только для чтения, называемый конечной точкой записи (изменение статуса).
404 not_found Бронирования с этим идентификатором у компании, владеющей ключом, нет.
409 conflict Изменение статуса привело бы к дублированию бронирования стола или места; ничего не изменилось.
422 invalid_status Значение поля «Статус» не входит в перечень допустимых значений для данного типа бронирования.
422 invalid_type Параметр type ленты событий не соответствует ни одному типу или семейству событий.
422 invalid_url URL подписки не является публичным адресом https.
429 rate_limited За эту минуту поступило более 50 запросов по этому ключу. Уменьшите частоту запросов и повторите попытку.
Нужен ключ?

Доступ к API, веб-хуки и интеграции с чатами и платформами автоматизации входят в каждый модуль — без доплаты и без отдельного тарифа для разработчиков.

Начните бесплатную пробную версию