Для разработчиков и ИИ

QRTap API — управляемые QR-коды из вашего кода

REST + JSON, ключ в заголовке Authorization: Bearer, спека OpenAPI 3.1, вебхуки сканов и MCP-сервер для ИИ-агентов. Ключ выпускается сразу и на бесплатном тарифе: первый рабочий код — за пять минут, без звонков, счетов и интеграционных совещаний.

Быстрый стартТарифы APIMCP для ИИГотовые интеграцииOpenAPI 3.1

Что такое QRTap

QRTap — платформа управляемых QR-кодов, коротких ссылок и публичных страниц, сделанная в Кыргызстане. Каждый код кодирует постоянную короткую ссылку https://app.qrtap.kg/{slug}. Куда она ведёт — это отдельная, версионируемая сущность: назначение меняется одним PATCH-запросом, а напечатанный тираж — меню, наклейки на оборудование, вкладыши в пакеты, визитки, наружная реклама — продолжает работать. Печать перестаёт быть точкой невозврата.

Поверх этого API отдаёт то, ради чего обычно и приходят интеграторы: пакетное создание до 500 кодов за вызов (идемпотентно по вашему external_ref), готовые артефакты PNG/SVG/PDF с проверкой читаемости, сборку клиенту страницы-визитки, два ящика мини-CRM (отзывы гостей и заявки на запись), умные правила редиректа по устройству, языку и часам, вебхуки на каждый скан и анонимную агрегированную статистику. Персональные данные посетителей не собираются вовсе: ни IP, ни user-agent не сохраняются — ни в статистике, ни в вебхуках.

Первый код за 5 минут

1Выпустить ключ — бесплатно

Регистрируетесь и выпускаете ключ сами: app.qrtap.kg/workspace/api. Платить, чтобы попробовать, не нужно: на бесплатном тарифе ключ выдаётся сразу — один ключ и 100 запросов в сутки, этого хватает, чтобы собрать интеграцию и показать её заказчику. Раздел доступен владельцу рабочего пространства. Ключ вида qrt_live_… показывается один раз: мы храним только его SHA-256-хеш. Ключ авторизует всю организацию и отзывается без простоя — на время ротации могут работать два ключа сразу.

export QRTAP_KEY=qrt_live_XXXX

2Создать код одним запросом

Ответ приходит сразу — с постоянной ссылкой и адресами картинок:

curl -X POST https://app.qrtap.kg/api/v1/codes \
  -H "Authorization: Bearer $QRTAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{"target_url":"https://example.com/menu",
       "label":"Меню, стол 5",
       "external_ref":"table-5",
       "group":"event_menu"}'

# 201 → {
#   "id": "8f1c…", "slug": "k3v9tqzx",
#   "short_url": "https://app.qrtap.kg/k3v9tqzx",
#   "png_url":  "https://app.qrtap.kg/api/v1/codes/8f1c…/qr?format=png",
#   "svg_url":  "https://app.qrtap.kg/api/v1/codes/8f1c…/qr?format=svg",
#   "target_url": "https://example.com/menu", "state": "deployed", …
# }

external_ref — ваш идентификатор (SKU, id партнёра, номер стола). Создание идемпотентно по нему: повтор того же external_ref вернёт существующий код, а не дубликат, поэтому вызов безопасно ретраить.

3Забрать готовый QR и отдать в печать

PNG для экрана и мессенджеров, SVG и PDF — для типографии. Каждый PNG перед отдачей декодируется обратно: если брендирование ухудшило читаемость, сервер откатится к простому коду и скажет об этом в заголовке X-QRTap-QA (branded | downgraded | plain).

curl -o qr.png -H "Authorization: Bearer $QRTAP_KEY" \
  "https://app.qrtap.kg/api/v1/codes/<id>/qr?format=png&size=2000"

# format: png | svg | pdf   size: 256…3000 (только png, по умолчанию 1024)
# errorCorrection: M | Q | H (по умолчанию Q)   caption: подпись под кодом (svg)

Всё. Дальше — смена назначения без перепечатки и статистика; напечатанная ссылка и short_url при этом не меняются никогда:

curl -X PATCH https://app.qrtap.kg/api/v1/codes/<id> \
  -H "Authorization: Bearer $QRTAP_KEY" -H "Content-Type: application/json" \
  -d '{"target_url":"https://example.com/new-landing"}'

curl -H "Authorization: Bearer $QRTAP_KEY" \
  "https://app.qrtap.kg/api/v1/codes/<id>/stats?from=2026-07-01T00:00:00Z"
# 200 → { "total": 128, "by_day": [{"day":"2026-07-20","count":68}],
#         "by_device": [{"device":"mobile","count":110}] }

Тарифы API

Отдельной подписки на API нет: лимиты — это лимиты вашего обычного тарифа QRTap. Бесплатный уровень существует, чтобы интеграцию можно было попробовать до покупки; граница продажи — не наличие ключа, а объём и набор возможностей за ним.

 FreeОсновной — 990 сом/месПолный — 1990 сом/мес
Запросов в сутки1005 00050 000
Ключей1310
Запросов в минуту60120300
Bulk и вебхукинетдада

Первый месяц тарифа «Основной» — 99 сом. Подробности и оплата — на странице тарифов.

Две вещи, которые лучше знать до того, как упрётесь. Суточная квота считается на рабочее пространство, а не на ключ: три ключа на «Основном» — это те же 5 000 запросов в сутки на всех, а не 15 000. Ключи нужны, чтобы разделять интеграции и отзывать их поштучно, а не чтобы умножать объём. И сутки считаются по UTC: квота обнуляется в полночь UTC, то есть в 6 утра по Бишкеку (в кабинете расход показан в бишкекском времени).

Что открывается на платном тарифе

Три возможности требуют платного тарифа. На бесплатном они отвечают 402 Payment Required с кодом plan_required — именно 402, а не 403: запрос корректен, не хватает тарифа, и после подключения тот же самый запрос сработает без единой правки в вашем коде.

  • POST /api/v1/codes/bulk — пакетное создание кодов.
  • /api/v1/webhooks целиком — регистрация, список и удаление вебхуков сканов.
  • PUT /api/v1/codes/{id}/smart-rules — умные правила редиректа (чтение через GET доступно всем).
# 402 → {
#   "error": "plan_required",
#   "detail": "Bulk creation is available on a paid plan. Your workspace is on FREE…",
#   "plan": "FREE",
#   "upgrade_url": "https://app.qrtap.kg/workspace/upgrade"
# }

Лимиты в бою: 429, заголовки и ретраи

Ограничителей два, и они разные по смыслу. Минутный — тормоз против разогнавшегося цикла: считается на каждый ключ отдельно, в памяти процесса, который обслужил запрос. При нескольких инстансах веба фактический потолок — лимит × число инстансов, поэтому цифра из таблицы это гарантированный минимум. Суточный — то, за что берут деньги: считается на всё рабочее пространство, хранится в базе, переживает перезапуск и общий для всех инстансов.

# Слишком часто → 429
{ "error": "rate_limited", "scope": "minute", "limit": 60, "remaining": 0,
  "reset_at": "2026-08-07T09:31:00.000Z", "retry_after": 24, "plan": "FREE",
  "detail": "Too fast: at most 60 requests per minute on the FREE plan…",
  "upgrade_url": "https://app.qrtap.kg/workspace/upgrade" }

# Кончилась суточная квота → тоже 429, но другой код
{ "error": "quota_exceeded", "scope": "day", "limit": 100, "remaining": 0,
  "reset_at": "2026-08-08T00:00:00.000Z", "retry_after": 52140, "plan": "FREE",
  "detail": "Daily quota spent: 100 requests per day on the FREE plan…" }

# Заголовки обоих отказов:
Retry-After: 24
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1786000260

Различайте scope: minute — подождите retry_after секунд и продолжайте, это временно; day — до reset_at (ближайшая полночь UTC) ждать бессмысленно, нужен тариф выше. upgrade_url приходит только тогда, когда апгрейд действительно поможет.

Важно для клиентской библиотеки: успешные ответы заголовки X-RateLimit-* не несут — они появляются только в ответе 429. Не стройте счётчик остатка на заголовках каждого ответа: их там нет. Расход за текущие сутки владелец видит в кабинете, а интеграция должна просто уважать Retry-After.

Не расходуют ни минутный лимит, ни суточную квоту: маршруты /api/v1/webhooks* (партнёр обязан суметь отозвать сломанный эндпоинт, даже исчерпав квоту) и всё, что вне /api/v1. Отказ по минутному тормозу суточную квоту не тратит. Отказ по тарифу (402) не тратит её там, где проверка тарифа идёт до учёта — на /api/v1/codes/bulk и /api/v1/webhooks*. У записи умных правил проверка живёт глубже, поэтому такой отказ расходует один запрос.

Аутентификация и ошибки

Каждый запрос — с ключом организации в заголовке Authorization: Bearer <ключ>:

Authorization: Bearer qrt_live_XXXX

Ошибки — JSON вида {"error":"...","detail":...}: 401 unauthorized (нет или отозван ключ), 400 invalid_request / invalid_url / invalid_id / invalid_group / unknown_design_template / invalid_image, 402 plan_required (bulk, вебхуки или умные правила на бесплатном тарифе), 404 not_found (в том числе для чужой организации — ID чужого тенанта неотличим от несуществующего), 422 invalid_content / invalid_rules / prohibited_content (последнее — подпись под кодом со стимулированием, запрещённым ст. 17 Закона КР «О рекламе»), 429 rate_limited и 429 quota_exceeded, 500 qa_failed (редкий сбой decode-проверки, безопасно повторить). Полный перечень по каждому эндпоинту — в OpenAPI-спеке.

Что умеет API v1

Семнадцать маршрутов, сгруппированных по задачам. Точные схемы запросов и ответов — в спеке.

  • POST /api/v1/codes — создать код; идемпотентно по external_ref.
  • POST /api/v1/codes/bulk — пакет до 500 кодов, результат по каждому элементу отдельно; одна плохая строка не роняет партию, весь вызов безопасно ретраить. Платный тариф.
  • GET /api/v1/codes — список с фильтрами group, external_ref, пагинацией (limit 1…500, offset) и include=stats (счётчик сканов всех кодов одним запросом).
  • GET /api/v1/codes/{id}, PATCH /api/v1/codes/{id} — чтение и смена назначения.
  • GET /api/v1/codes/{id}/history — все назначения кода (аудит, новые сверху).
  • GET /api/v1/codes/{id}/stats и GET /api/v1/groups/{group}/stats — агрегаты по коду и по целому типу кодов (partner, equipment, event_menu, bag_insert, training).
  • GET /api/v1/codes/{id}/qr — артефакт PNG / SVG / PDF; брендированный, когда у кода есть шаблон дизайна.
  • POST /api/v1/design-templates, GET /api/v1/design-templates — фирменный вид: цвет модулей + логотип в центре (data URI, санитизируется на сервере). Гейт decode-QA следит, чтобы код оставался считываемым.
  • POST /api/v1/webhooks, GET /api/v1/webhooks, DELETE /api/v1/webhooks/{id} — вебхуки сканов, см. ниже. Платный тариф.
  • GET /api/v1/pages, POST /api/v1/pages, GET /api/v1/pages/{slug}, PATCH /api/v1/pages/{slug} — страницы-визитки, см. ниже.
  • GET /api/v1/reviews, POST /api/v1/reviews/{id}/moderate — отзывы гостей и модерация.
  • GET /api/v1/bookings, POST /api/v1/bookings/{id}/status — заявки на запись и решение по ним.
  • GET /api/v1/codes/{id}/smart-rules, PUT /api/v1/codes/{id}/smart-rules — умные правила редиректа (устройство, язык, часы). Запись — платный тариф.

Пакет и группы

Партия кодов — один вызов; пакетное создание доступно на платном тарифе (на бесплатном — 402 plan_required). Элементы обрабатываются независимо, ответ содержит created, failed и data с построчным итогом (ok: true и сам код либо ok: false с external_ref и кодом ошибки). Сводная статистика снимается по всей группе разом.

curl -X POST https://app.qrtap.kg/api/v1/codes/bulk \
  -H "Authorization: Bearer $QRTAP_KEY" -H "Content-Type: application/json" \
  -d '[{"target_url":"https://example.com/p/1","external_ref":"SMK-P-001","group":"partner"},
       {"target_url":"https://example.com/p/2","external_ref":"SMK-P-002","group":"partner"}]'

# 201 → { "created": 2, "failed": 0, "data": [ {"ok":true, …}, {"ok":true, …} ] }

curl -H "Authorization: Bearer $QRTAP_KEY" \
  "https://app.qrtap.kg/api/v1/groups/partner/stats"
# 200 → { "group":"partner", "codes": 2, "total": 41, "by_day":[…], "by_device":[…] }

Страницы-визитки

Страница живёт по адресу https://app.qrtap.kg/a/{slug}. Один POST собирает её целиком, ответ содержит public_url — наведите на него QR-код, и получится готовая визитка для печати. Повторный POST не создаёт вторую страницу: он публикует новую версию той же страницы, slug не меняется, поэтому напечатанный код продолжает работать. Контент санитизируется на сервере: телефон нормализуется, выживают только http/https-ссылки, лишние поля отбрасываются.

# 1. Собрать и опубликовать страницу
curl -X POST https://app.qrtap.kg/api/v1/pages \
  -H "Authorization: Bearer $QRTAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content":{
        "segment":"otzyvy","theme":"emerald",
        "name":"Кофейня «Тандем»","specialty":"Спешелти-кофе в центре",
        "phone":"0555 123 456","hours":"ежедневно 8:00–22:00",
        "address":"Бишкек, ул. Киевская 100",
        "services":[{"name":"Фильтр-кофе","price":"180 сом"}],
        "reviewLinks":{"twogis":"https://2gis.kg/bishkek/firm/70000001"}}}'

# 201 → { "slug": "cozy-cafe-x1", "public_url": "https://app.qrtap.kg/a/cozy-cafe-x1", … }

# 2. Навести на неё QR-код
curl -X POST https://app.qrtap.kg/api/v1/codes \
  -H "Authorization: Bearer $QRTAP_KEY" -H "Content-Type: application/json" \
  -d '{"target_url":"https://app.qrtap.kg/a/cozy-cafe-x1","label":"Визитка «Тандем»"}'

# 3. Обновить содержимое — slug и печать не меняются
curl -X PATCH https://app.qrtap.kg/api/v1/pages/cozy-cafe-x1 \
  -H "Authorization: Bearer $QRTAP_KEY" -H "Content-Type: application/json" \
  -d '{"content":{"name":"Кофейня «Тандем»","phone":"0555 123 456","hours":"пн–сб 9:00–21:00"}}'

# 4. Список страниц (без контента)
curl https://app.qrtap.kg/api/v1/pages -H "Authorization: Bearer $QRTAP_KEY"

PATCH заменяет контент целиком — если нужно поправить одно поле, сначала прочитайте страницу через GET /api/v1/pages/{slug}. Обязательны имя и хотя бы один контакт (телефон, WhatsApp, Instagram или ссылка на запись), иначе 422 invalid_content.

Отзывы и заявки на запись

Всё, что гость оставил на публичной странице, попадает в два ящика организации. Отзыв не виден никому, пока владелец его не опубликовал, — status=pending и есть очередь модерации. Хранится только то, что гость набрал сам: ни IP, ни user-agent.

# Очередь модерации отзывов
curl "https://app.qrtap.kg/api/v1/reviews?status=pending" \
  -H "Authorization: Bearer $QRTAP_KEY"
# 200 → { "data": [{ "id": "…", "author_name": "Айгуль",
#          "body": "Очень уютно, спасибо!", "status": "pending", … }] }

# Опубликовать отзыв (или скрыть: {"action":"hide"})
curl -X POST https://app.qrtap.kg/api/v1/reviews/<id>/moderate \
  -H "Authorization: Bearer $QRTAP_KEY" -H "Content-Type: application/json" \
  -d '{"action":"publish"}'

# Новые заявки на запись
curl "https://app.qrtap.kg/api/v1/bookings?status=new" \
  -H "Authorization: Bearer $QRTAP_KEY"
# 200 → { "data": [{ "id": "…", "service": "Маникюр",
#          "preferred_at": "завтра после 14:00", "guest_name": "Айгуль",
#          "guest_phone": "0555 123 456", "status": "new", … }] }

# Подтвердить или отклонить
curl -X POST https://app.qrtap.kg/api/v1/bookings/<id>/status \
  -H "Authorization: Bearer $QRTAP_KEY" -H "Content-Type: application/json" \
  -d '{"status":"confirmed"}'

preferred_at — свободный текст в том виде, как его набрал гость; платформа его не разбирает. Гостю QRTap ничего не отправляет: связаться с ним — по телефону из заявки. Вернуть заявку в статус new через API нельзя.

Умные правила (Smart Links)

Правила проверяются на каждом скане: побеждает первое совпавшее, если не совпало ничего — работает основное назначение кода. Сломанный или нечитаемый набор правил тоже деградирует к основному назначению, поэтому напечатанный код не сломать. Максимум 5 правил; [] или null очищает набор. Нужен платный тариф (иначе 402 plan_required).

curl -X PUT https://app.qrtap.kg/api/v1/codes/<id>/smart-rules \
  -H "Authorization: Bearer $QRTAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{"rules":[
        {"if":{"kind":"device","in":["ios"]},"to":"https://apps.apple.com/app/id1"},
        {"if":{"kind":"device","in":["android"]},"to":"https://play.google.com/store/apps/details?id=kg.qrtap"},
        {"if":{"kind":"hours","tz":"Asia/Bishkek","from":"22:00","to":"09:00"},
         "to":"https://example.com/night-menu"}]}'

# Текущие правила
curl https://app.qrtap.kg/api/v1/codes/<id>/smart-rules \
  -H "Authorization: Bearer $QRTAP_KEY"

Условия: device (ios | android | desktop | other), lang (коды вида ru, ky) и hours (tz — IANA-зона, from/to — ЧЧ:ММ, to исключительно, окно через полночь допустимо, days — 1=пн…7=вс). Правила видят только огрублённые признаки: сырые IP, User-Agent и Accept-Language не сохраняются никогда.

Вебхуки сканов

Зарегистрируйте HTTPS-адрес — и на каждый скан ваших кодов придёт POST. В ответе на регистрацию один раз показывается signing_secret (префикс whsec_); сохраните его для проверки подписи. Вебхуки — платный тариф (иначе 402 plan_required); при этом сами маршруты /api/v1/webhooks* не расходуют ни минутный лимит, ни суточную квоту.

curl -X POST https://app.qrtap.kg/api/v1/webhooks \
  -H "Authorization: Bearer $QRTAP_KEY" -H "Content-Type: application/json" \
  -d '{"url":"https://your-service.example/qrtap/scan"}'
# 201 → { "id": "…", "url": "…", "active": true, "signing_secret": "whsec_…" }

# Каждый скан прилетает так:
POST <ваш url>
X-QRTap-Event: scan
X-QRTap-Signature: sha256=<hex>
Content-Type: application/json

{ "code_id": "…", "external_ref": "SMK-P-001", "group": "partner",
  "ts": "2026-07-20T12:34:56.000Z", "device_type": "mobile" }

Подпись — HMAC-SHA256 от сырого тела запроса на вашем signing_secret; сравните hex-дайджест со значением после sha256=:

import { createHmac, timingSafeEqual } from "node:crypto";

const expected = createHmac("sha256", process.env.QRTAP_WEBHOOK_SECRET)
  .update(rawBody)
  .digest("hex");
const given = signatureHeader.replace(/^sha256=/, "");
const ok =
  given.length === expected.length &&
  timingSafeEqual(Buffer.from(given, "hex"), Buffer.from(expected, "hex"));

Доставка — at-least-once: отвечайте любым 2xx в течение 8 секунд, обработчик делайте идемпотентным. Не-2xx или таймаут ретраятся с экспоненциальной паузой (порядка 2n минут, максимум 12 часов между попытками), всего до 8 попыток. В payload нет персональных данных — только идентификаторы кода, ваши референсы, время и класс устройства.

Спека, MCP и готовые сценарии

  • app.qrtap.kg/openapi.json — полная спека OpenAPI 3.1: генерируйте клиентов, импортируйте в Postman или Insomnia, отдавайте ИИ-агентам.
  • /llms.txt и /llms-full.txt — описание сервиса для языковых моделей: короткий индекс и развёрнутое описание всех возможностей.
  • app.qrtap.kg/mcp — MCP-сервер (npm-пакет qrtap-mcp): 20 инструментов для Claude Desktop, Claude Code и любого MCP-совместимого ассистента, готовый блок конфигурации.
  • app.qrtap.kg/integrations — готовые сценарии подключения: CRM, POS и чеки, Telegram-бот, таблицы, no-code-автоматизация, типография.

Использование API регулируют Условия использования API, а также оферта и политика конфиденциальности. Коротко: за содержимое ссылок, на которые ведут ваши коды, отвечаете вы; перепродажа доступа к API и обход лимитов запрещены.

На главную · MCP · Интеграции · OpenAPI · Тарифы · Поддержка · Условия API