QRFLOW.codes

официальный

Создавайте QR-коды, перенаправляйте напечатанные динамические коды, называйте ссылки на своём домене и читайте аналитику сканирований.

Что можно делать с QRFLOW Codes MCP?

  • Создание динамических QR-кодов — Попросите сгенерировать печатаемый short_url для любого URL-адреса, с возможностью изменить пункт назначения в любое время после печати.
  • Перенаправление напечатанных кодов — Запросите обновление destination_data кода на новый URL-адрес; существующие напечатанные коды продолжат работать без повторной печати.
  • Получение аналитики сканирований — Запросите разбивку Scans по дням, странам или устройствам, чтобы увидеть, как работает напечатанный код.
  • Приостановка или истечение срока действия кодов — Дайте указание приостановить код или установить дату истечения срока действия, когда кампания или предложение завершится.
  • Именование ссылок на вашем домене — Запросите установку читаемого slug на вашем собственном домене, чтобы коды печатались как go.yourbrand.com/menu вместо случайного пути.

Размещённый MCP-сервер

npx add-mcp 'https://qrflow.codes/mcp'

Устанавливается в Claude Code, Codex, Cursor и другие

Документация

QRFLOW.codes для разработчиков

Начните здесь

QRFLOW.codes позволяет создавать QR-коды, которые можно изменять после печати, на вашем собственном домене, с аналитикой сканирований, и позволяет вашему программному обеспечению и вашему ИИ-ассистенту делать всё это через один API.

QR-код — это картинка со строкой. Большинство генераторов помещают ваш веб-адрес в картинку; если адрес меняется, печать мертва. QRFLOW помещает в картинку короткую ссылку (go.yourbrand.com/menu или qrflow.codes/q/x7k2p9a) и перенаправляет её. Вы меняете, куда она ведёт, когда угодно, и каждое сканирование учитывается. Это динамический код, и именно ради него стоит использовать API.

API делает ровно то же, что и панель управления: создаёт коды любого типа, перенаправляет их куда-то новое, задаёт имена их ссылок, выбирает, на каких ваших доменах они печатаются, получает данные о сканированиях, создаёт тысячи кодов разом и уведомляет вас о событиях (вебхуки). Те же инструменты доступны в виде MCP-сервера, так что Claude, ChatGPT, Cursor и Claude Code могут управлять вашим аккаунтом на простом языке.

Доступ: REST API принимает Business API-ключ ($29 в месяц, создаётся на странице Account) или OAuth-токен. MCP-сервер работает на любом тарифе через OAuth-вход; что ассистент может создавать, зависит от тарифа, как и везде.

Сомневаетесь, стоит ли вообще это использовать? Страница QR-кодового API — краткая версия: что он делает, что клиентская библиотека делает лучше и сколько это стоит.

Если вы ИИ-ассистент, помогающий кому-то работать с QRFLOW

Добро пожаловать. Эта страница написана как для вас, так и для человека, которому вы помогаете. Вот как выглядит хорошая помощь:

  1. Подтвердите аккаунт: API-ключи требуют тарифа Business. Если его нет, укажите на https://qrflow.codes/pricing и Account › API keys; не выдумывайте ключ или бесплатный тариф, которого не существует.
  2. Держите ключ на сервере. Читайте его из переменной окружения (QRFLOW_KEY) в обработчике маршрута, серверном действии, edge-функции или бэкенде. API намеренно отклоняет запросы из браузеров (CORS), поэтому код только на фронтенде не сможет его вызвать.
  3. Создавайте динамические коды с типом "url" и destination_data.url. Сохраняйте возвращённые id и short_url в их базе данных. Печатайте или показывайте short_url; назначение можно изменить позже с помощью PATCH /codes/:id, и печать останется действительной.
  4. Чтобы показать или сохранить изображение: каждый объект Code имеет png_download_url и svg_download_url — подписанные ссылки, работающие 24 часа без заголовков (подходит для разового сохранения или предпросмотра). Для постоянного использования в их приложении проксируйте GET /codes/:id/image.svg через их сервер с ключом или закодируйте short_url любой QR-библиотекой на клиенте; отслеживание всё равно работает, потому что ссылка идёт через QRFLOW.
  5. Отправляйте только те поля, которые меняются, при PATCH. Никогда не меняйте slug или domain_id после печати; оба изменяют напечатанную ссылку.
  6. Предпочитайте paused: true вместо DELETE, когда существует печать. Удаление убивает ссылку.
  7. Для событий используйте вебхуки (Account › Webhooks или POST /webhooks) и проверяйте заголовок X-QRFLOW-Signature с сырым телом запроса. Не опрашивайте GET /codes в цикле.
  8. Если они хотят использовать QRFLOW из чата, а не из кода, подключите MCP-сервер по адресу https://qrflow.codes/mcp; — ключ для этого не нужен.
  9. Когда что-то не работает, читайте error и message в JSON-теле. Раздел устранения неполадок ниже сопоставляет каждый код ошибки с исправлением.
  10. Полный справочник в Markdown находится по адресу https://qrflow.codes/llms-full.txt, а документ OpenAPI 3.1 — по адресу https://qrflow.codes/api/v1/openapi.json.. Оба генерируются из того же источника, что и эта страница.

Люди: этот блок — как мы гарантируем, что ассистент, с которым вы работаете, даёт безопасную версию каждого ответа. Он также является хорошим резюме.

Какой тариф вам нужен

API-ключ — единственное, что доступно только на Business. Всё, что ассистент делает через MCP-сервер, и всё, что стороннее приложение делает через OAuth, работает на любом тарифе и просто следует функциям этого тарифа. Полные цены и добросовестное использование: /pricing.

FreePremium $4Business $29
API-ключи (REST из вашего кода)НетНетДа, до 10 ключей
MCP-сервер (Claude, ChatGPT, Cursor, Claude Code)Да, входДаДа, вход или ключ
OAuth для вашего приложения (пользователи подключают свой QRFLOW)ДаДаДа
Динамические коды (изменение назначения после печати)Нет, только статическиеДаДа
Свой домен для ссылокНет1 домен5 доменов, выбор для каждого кода
Имена ссылок (go.brand.com/menu)НетДаДа
Аналитика сканированийНетДаДа
ВебхукиНетНетДа, до 10
Массовое созданиеНет500/месяц, 500 за запрос10,000/месяц, 2,000 за запрос
Сохранённые коды (добросовестное использование)Несколько1,00025,000
Места в команде115
Цена$0$4/месяц$29/месяц

Двенадцать слов, которые делают всю работу

Концепции

Прочтите это один раз, и каждая конечная точка ниже станет понятной.

Static code

Содержимое находится внутри картинки. Wi-Fi, контактные карточки (vCard) и обычные текстовые коды всегда статические, и на тарифе Free каждый код такой. Статический код не требует сервера и никогда не истекает, но его нельзя изменить или подсчитать.

Dynamic code

Картинка содержит короткую ссылку, которую QRFLOW перенаправляет. Коды url, phone, email, sms и location являются динамическими на Premium и Business. Вы можете перенаправлять, приостанавливать, устанавливать срок действия, переименовывать и подсчитывать их, не трогая печать.

short_url

Точная строка, закодированная в динамическом коде, и то, что нужно печатать. Это https://qrflow.codes/q/<short_code> пока вы не подключите домен, затем https://<your domain>/<slug or short_code>.. Каждый объект Code содержит её.

short_code

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

slug (link name)

Читаемый путь на вашем собственном домене: go.example.com/menu. От 3 до 40 строчных букв, цифр и дефисов, уникальный в пределах вашего аккаунта, только с подключённым доменом. Установите его до печати: его изменение меняет напечатанную ссылку.

Link domain

Имя хоста, которым вы владеете (go.example.com), указывающее на QRFLOW через CNAME и проверенное на странице Account. Premium получает один; Business получает пять и может выбирать для каждого кода с помощью domain_id. Самый старый активный домен используется по умолчанию.

Kind, type and subtype

type — это кодировка: url, text, wifi, vcard, email, phone, sms, location. kind — более дружелюбное имя для того, что нужно людям (instagram, googlereview, whatsapp, pdf, menu, appstore,...). Большинство kinds — это url-коды с установленным destination_data.subtype. GET /catalog перечисляет каждый kind с его полями; kind на Code говорит вам, какой это.

destination_data

Поля для типа, как строки: { url } для веб-сайта, { ssid, password, encryption } для Wi-Fi, { placeId } для отзыва Google, { handle } для Instagram. На динамическом коде вы можете заменить их в любое время.

Scans

Каждое перенаправление записывает тип устройства, страну, город, реферера, браузер, ОС и язык из самого запроса, плюс односторонний ежедневный хэш для подсчёта уникальных посетителей. Файлы cookie не устанавливаются, IP-адрес не хранится. scans на Code — это общее количество за всё время; GET /codes/:id/scans разбивает его по деталям.

Source

Каждый код помнит, что его создало: dashboard, api:<key name>, mcp, canva или bulk. Это отображается в панели управления и в полезных нагрузках вебхуков, так что вы можете отличить коды вашей интеграции от созданных вручную.

Workspace

Владелец Business может пригласить до четырёх коллег. Ключи и вебхуки принадлежат аккаунту владельца; коды, созданные кем-либо в рабочем пространстве, видны всей команде.

Пять минут

Быстрый старт

Получите ключ

  1. На тарифе Business откройте Account › API keys.
  2. Назовите его по назначению ("Бэкенд магазина", "Отчётность") и выберите его области. Области нельзя изменить позже; создайте новый ключ, если нужно больше.
  3. Скопируйте его один раз. Он выглядит как qrf_live_…. Поместите его в переменную окружения с именем QRFLOW_KEY.
  4. Отправляйте его как Authorization: Bearer $QRFLOW_KEY в каждом запросе. Это вся история аутентификации.

Ключи предназначены для серверов. Никогда не помещайте его на веб-страницу, в мобильное приложение или общую таблицу; отзывайте и перевыпускайте, если он утёк.

Те же пять шагов в curl, TypeScript и Python. Каждый создаёт динамический код, загружает его изображение, меняет, куда он ведёт, и читает его сканирования.

export QRFLOW_KEY=qrf_live_...   # from Account › API keys

# 1. Who am I, what can this key do?
curl https://qrflow.codes/api/v1/me -H "Authorization: Bearer $QRFLOW_KEY"

# 2. Make a dynamic code. Print what comes back as short_url.
curl -X POST https://qrflow.codes/api/v1/codes \
  -H "Authorization: Bearer $QRFLOW_KEY" -H "Content-Type: application/json" \
  -d '{ "type": "url", "destination_data": { "url": "https://example.com/menu" }, "label": "Table tents" }'

# 3. The print-ready image (SVG, with your colors and frame).
curl "https://qrflow.codes/api/v1/codes/$CODE_ID/image.svg?size=1024" \
  -H "Authorization: Bearer $QRFLOW_KEY" -o menu.svg

# 4. Fall menu. The printed code keeps working.
curl -X PATCH https://qrflow.codes/api/v1/codes/$CODE_ID \
  -H "Authorization: Bearer $QRFLOW_KEY" -H "Content-Type: application/json" \
  -d '{ "destination_data": { "url": "https://example.com/menu-fall" } }'

# 5. How did it do?
curl "https://qrflow.codes/api/v1/codes/$CODE_ID/scans?group=day" -H "Authorization: Bearer $QRFLOW_KEY"

TypeScript (Node 18+, Bun, Deno, Workers)

// npm install qrflow   (zero dependencies; ESM + CommonJS; full types)
import { QRFlow, QRFlowError } from "qrflow";

const qr = new QRFlow(process.env.QRFLOW_KEY!);

const { code } = await qr.createCode({
  type: "url",
  destination_data: { url: "https://example.com/menu" },
  label: "Table tents",
});
console.log(code.id, code.short_url);        // save both; print short_url

await qr.updateCode(code.id, { destination_data: { url: "https://example.com/menu-fall" } });

const stats = await qr.scans(code.id, { group: "day" });
console.log(stats.total, stats.rows);         // [{ key: "2026-09-21", scans: 18 }, ...]

try {
  await qr.updateCode(code.id, { slug: "menu" });
} catch (e) {
  if (e instanceof QRFlowError) console.log(e.status, e.code, e.message); // 400 no_domain: connect a domain first
}
# Download https://qrflow.codes/sdk/qrflow.py next to your code.
import os
from qrflow import QRFlow, QRFlowError

qr = QRFlow(os.environ["QRFLOW_KEY"])

code = qr.create_code(type="url", destination_data={"url": "https://example.com/menu"}, label="Table tents")["code"]
print(code["id"], code["short_url"])          # save both; print short_url

qr.update_code(code["id"], destination_data={"url": "https://example.com/menu-fall"})

stats = qr.scans(code["id"], group="day")
print(stats["total"], stats["rows"])

try:
    qr.update_code(code["id"], slug="menu")
except QRFlowError as e:
    print(e.status, e.code, e)                # 400 no_domain: connect a domain first

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

API-ключи (Business)

До 10 на аккаунт, 600 запросов в минуту каждый, хранятся в хэшированном виде, показываются один раз. Ключ несёт области, с которыми он был создан:

ОбластьРазрешает
profileGET /me: тариф, функции, лимиты. Есть у каждого ключа.
codes:readСписок и чтение кодов, загрузка изображений.
codes:writeСоздание, изменение, превращение в динамические, удаление, массовое создание.
analytics:readGET /codes/:id/scans.
domains:readGET /domains (нужно для осмысленного использования domain_id).
webhooks:manageСписок, создание, тестирование и удаление вебхуков.

OAuth 2.0 (любой тариф, для приложений и ассистентов)

Когда коды должны принадлежать аккаунтам ваших пользователей, а не вашим, или когда клиентом является чат-ассистент, используйте OAuth. Клиенты регистрируют себя сами; PKCE S256 обязателен для публичных клиентов; токены могут быть привязаны к MCP-серверу с помощью resource=. Рецепт OAuth проводит через весь процесс.

Конечная точкаURLПримечания
Авторизацияhttps://qrflow.codes/oauth/authorizeОтправьте пользователя сюда; он входит и нажимает Разрешить.
Токенhttps://qrflow.codes/api/oauth/tokenГранты authorization_code и refresh_token. Токены доступа живут 1 час, токены обновления — 90 дней.
Отзывhttps://qrflow.codes/api/oauth/revokeRFC 7009. Пользователи также могут отключиться в Account › Connected apps.
Регистрация клиентаhttps://qrflow.codes/api/oauth/registerДинамическая регистрация RFC 7591, аккаунт не нужен. Публичные клиенты получают dyn_ client_id и должны использовать PKCE S256.
Обнаружениеhttps://qrflow.codes/.well-known/oauth-authorization-serverRFC 8414. Документ ресурса MCP находится по адресу /.well-known/oauth-protected-resource.

Токены доступа живут 1 час, токены обновления — 90 дней. Пользователи видят подключённые приложения в Account › Connected apps и могут отключиться в любое время. Токен, выпущенный для https://qrflow.codes/mcp, отклоняется на /api/v1, и наоборот.

То, о чём люди действительно спрашивают

Рецепты сборки

Каждый рецепт полный и скопирован прямо из рабочего кода. Выберите тот, который соответствует вашему стеку; форма всегда одна и та же: серверный вызов с ключом, сохранение id и short_url, показ изображения.

Next.js: маршрут, который создаёт код, и маршрут, который его показывает

Когда: У вас есть приложение Next.js (App Router), и вы хотите кнопку, которая создаёт QR-код, и страницу, которая его отображает.

  1. Поместите ваш ключ в .env.local как QRFLOW_KEY. Никогда не добавляйте префикс NEXT_PUBLIC_.
  2. Добавьте POST-обработчик маршрута, который создаёт код и возвращает id и short_url.
  3. Добавьте GET-маршрут, который проксирует изображение, чтобы браузер никогда не видел ключ.
  4. Сохраните id и short_url в вашей собственной записи (заказ, стол, товар, событие).
import { NextResponse } from "next/server";

export async function POST(req: Request) {
  const { url, label } = await req.json();
  const r = await fetch("https://qrflow.codes/api/v1/codes", {
    method: "POST",
    headers: { Authorization: \`Bearer ${process.env.QRFLOW_KEY}\`, "Content-Type": "application/json" },
    body: JSON.stringify({ type: "url", destination_data: { url }, label }),
  });
  const data = await r.json();
  if (!r.ok) return NextResponse.json(data, { status: r.status }); // { error, message }
  return NextResponse.json({ id: data.code.id, short_url: data.code.short_url });
}
// Proxies the SVG so the key stays on the server. Check that the signed-in
// user owns this id before you serve it, or anyone with an id can fetch it.
export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;
  const r = await fetch(\`https://qrflow.codes/api/v1/codes/${id}/image.svg?size=1024\`, {
    headers: { Authorization: \`Bearer ${process.env.QRFLOW_KEY}\` },
  });
  return new Response(r.body, {
    status: r.status,
    headers: { "Content-Type": "image/svg+xml", "Cache-Control": "private, max-age=3600" },
  });
}
<img src={\`/api/qr/${code.id}/image\`} alt={\`QR code for ${code.label}\`} width={256} height={256} />
<a href={code.short_url}>{code.short_url}</a>
  • Серверные действия работают так же: вызывайте fetch с ключом внутри действия.
  • Для Pages Router тот же код идёт в pages/api/qr.ts с req/res.

Показ QR без проксирования: рендерите short_url сами

Когда: Вы хотите изображение в браузере немедленно, и вам не нужны рамки или логотип QRFLOW на нём. Любая QR-библиотека подойдет, потому что код И ЕСТЬ короткая ссылка

import QRCode from "qrcode"; // npm i qrcode

// short_url came back from POST /codes. Encode it as-is.
const dataUrl = await QRCode.toDataURL(code.short_url, { width: 512, margin: 2 });
// <img src={dataUrl} />  scans go through QRFLOW, so analytics and re-pointing still work.
  • Это самый быстрый путь для предпросмотра. Для печати скачайте /codes/:id/image.svg: он сохраняет выбранные цвета, рамку, подписи и логотип, и это вектор.
  • Если позже вы измените slug или domain_id, short_url изменится; перерендерите.

Express или любой Node-сервер

Когда: обычный Node-бэкенд.

import express from "express";
const app = express();
app.use(express.json());
const H = { Authorization: \`Bearer ${process.env.QRFLOW_KEY}\`, "Content-Type": "application/json" };

app.post("/qr", async (req, res) => {
  const r = await fetch("https://qrflow.codes/api/v1/codes", {
    method: "POST", headers: H,
    body: JSON.stringify({ type: "url", destination_data: { url: req.body.url }, label: req.body.label }),
  });
  res.status(r.status).json(await r.json());
});

app.get("/qr/:id.svg", async (req, res) => {
  const r = await fetch(\`https://qrflow.codes/api/v1/codes/${req.params.id}/image.svg\`, { headers: H });
  res.status(r.status).type("image/svg+xml").send(await r.text());
});

app.listen(3000);

Cloudflare Workers, Vercel Edge, Deno Deploy, Supabase Edge Functions

Когда: среда выполнения только с fetch, без встроенных модулей Node.

export default {
  async fetch(req: Request, env: { QRFLOW_KEY: string }) {
    const { url, label } = await req.json();
    const r = await fetch("https://qrflow.codes/api/v1/codes", {
      method: "POST",
      headers: { Authorization: \`Bearer ${env.QRFLOW_KEY}\`, "Content-Type": "application/json" },
      body: JSON.stringify({ type: "url", destination_data: { url }, label }),
    });
    return new Response(r.body, { status: r.status, headers: { "Content-Type": "application/json" } });
  },
};
Deno.serve(async (req) => {
  const { url, label } = await req.json();
  const r = await fetch("https://qrflow.codes/api/v1/codes", {
    method: "POST",
    headers: { Authorization: \`Bearer ${Deno.env.get("QRFLOW_KEY")}\`, "Content-Type": "application/json" },
    body: JSON.stringify({ type: "url", destination_data: { url }, label }),
  });
  return new Response(await r.text(), { status: r.status, headers: { "Content-Type": "application/json" } });
});
// supabase secrets set QRFLOW_KEY=qrf_live_...
  • npm-пакет qrflow\ использует только fetch и WebCrypto, поэтому работает во всех этих средах без изменений.

Python: FastAPI, Flask, Django, скрипт

Когда: ваш бэкенд на Python.

import os
from fastapi import FastAPI, HTTPException, Response
from qrflow import QRFlow, QRFlowError   # https://qrflow.codes/sdk/qrflow.py

app = FastAPI()
qr = QRFlow(os.environ["QRFLOW_KEY"])

@app.post("/qr")
def make_qr(url: str, label: str | None = None):
    try:
        code = qr.create_code(type="url", destination_data={"url": url}, label=label)["code"]
    except QRFlowError as e:
        raise HTTPException(e.status, {"error": e.code, "message": str(e)})
    return {"id": code["id"], "short_url": code["short_url"]}

@app.get("/qr/{code_id}.svg")
def qr_image(code_id: str):
    import urllib.request
    req = urllib.request.Request(qr.image_url(code_id), headers={"Authorization": f"Bearer {os.environ['QRFLOW_KEY']}"})
    with urllib.request.urlopen(req) as r:
        return Response(r.read(), media_type="image/svg+xml")

Один QR-код на заказ, столик, товар, билет или событие

Когда: каждой строке в одной из ваших таблиц нужен свой код, создаваемый автоматически.

  1. Добавьте два столбца в таблицу: qrflow_code_id (uuid) и qr_short_url (text).
  2. При создании строки отправьте POST /codes с публичным URL строки и меткой, которая ее называет («Заказ 10432», «Столик 7»). Сохраните id и short_url.
  3. Когда страница строки переезжает (новый домен, новый путь), отправьте PATCH destination_data. Напечатанные коды продолжат работать.
  4. Когда строка выводится из эксплуатации, отправьте PATCH { paused: true }, если что-то было напечатано; DELETE — только если ничего не печаталось.
  5. Нужны тысячи кодов сразу (меню на каждый столик для 300 ресторанов)? Используйте POST /codes/bulk порциями и сопоставьте возвращенные коды со строками по метке или порядку.
const { code } = await qr.createCode({
  type: "url",
  destination_data: { url: \`https://example.com/orders/${order.id}\` },
  label: \`Order ${order.number}\`,
});
await db.orders.update(order.id, { qrflow_code_id: code.id, qr_short_url: code.short_url });
  • Добросовестное использование — 25 000 сохраненных кодов на тарифе Business; API останавливается на вдвое большем количестве. Если вам нужен код на каждый чек навсегда, сначала свяжитесь с нами: hello@qrflow.codes.

Изменение назначения напечатанного кода

Когда: кампания завершилась, страница переехала, PDF заменен, сезон сменился.

curl -X PATCH https://qrflow.codes/api/v1/codes/$CODE_ID \
  -H "Authorization: Bearer $QRFLOW_KEY" -H "Content-Type: application/json" \
  -d '{ "destination_data": { "url": "https://example.com/spring" } }'

Приостановите его или задайте дату окончания

# Scans show a "paused" page instead of redirecting
curl -X PATCH https://qrflow.codes/api/v1/codes/$CODE_ID -H "Authorization: Bearer $QRFLOW_KEY" \
  -H "Content-Type: application/json" -d '{ "paused": true }'

# Stops working after the date; null clears it
curl -X PATCH https://qrflow.codes/api/v1/codes/$CODE_ID -H "Authorization: Bearer $QRFLOW_KEY" \
  -H "Content-Type: application/json" -d '{ "expires_at": "2026-12-31T23:59:59Z" }'
  • Только динамические коды можно перенаправлять. Код url, созданный на бесплатном аккаунте, или код Wi-Fi/vCard/текста отвечает 400 not_dynamic. Для кода url/телефона/email/sms/местоположения на платном тарифе POST /codes/:id/dynamic конвертирует его, и вам нужно перерендерить и перепечатать, потому что картинка меняется.
  • Сканер увидит новый адрес назначения при следующем сканировании. Кэша, который нужно ждать, нет.

Печать кодов на вашем собственном домене

Когда: вы хотите видеть go.example.com/menu в коде вместо qrflow.codes/q/x7k2p9a.

  1. На странице Account, в разделе Your own link domain, добавьте go.example.com и создайте CNAME, который вам покажут, у вашего DNS-провайдера. Проверка обычно завершается за несколько минут.
  2. С этого момента short_url каждого нового динамического кода использует этот домен. Существующие коды тоже переключаются: их картинка кодировала qrflow.codes/q/..., который продолжает перенаправлять, так что ничего напечатанное не ломается.
  3. Давайте кодам читаемые имена с помощью slug: PATCH { "slug": "menu" } создает go.example.com/menu. Делайте это до печати.
  4. На тарифе Business с несколькими доменами GET /domains перечисляет их с id; передавайте domain_id в POST или PATCH, чтобы выбрать для каждого кода.

Назовите ссылку и выберите домен

curl https://qrflow.codes/api/v1/domains -H "Authorization: Bearer $QRFLOW_KEY"
# { "default_base": "https://go.example.com", "domains": [ { "id": "…", "host": "go.example.com", "is_default": true, … }, { "id": "…", "host": "qr.example.fr", … } ] }

curl -X PATCH https://qrflow.codes/api/v1/codes/$CODE_ID -H "Authorization: Bearer $QRFLOW_KEY" -H "Content-Type: application/json" \
  -d '{ "slug": "menu", "domain_id": "<id of qr.example.fr>" }'
# short_url is now https://qr.example.fr/menu

График сканирований в вашей собственной админке

Когда: вы хотите видеть сканирования в день, по странам или по устройствам рядом со своими цифрами.

const stats = await qr.scans(code.id, { from: "2026-09-01", to: "2026-09-30", group: "day" });
// stats.total -> 412
// stats.rows  -> [{ key: "2026-09-01", scans: 18 }, { key: "2026-09-02", scans: 25 }, ...]
// Feed rows straight into Recharts, Chart.js, or a <table>.

const byCountry = await qr.scans(code.id, { group: "country" });   // [{ key: "US", scans: 300 }, { key: "MX", scans: 41 }]
const byDevice  = await qr.scans(code.id, { group: "device" });    // mobile, desktop, tablet
  • Один запрос покрывает до 92 дней; для более длинных диапазонов используйте цикл. Даты в UTC.
  • Для живых цифр без опроса подпишите вебхук на событие scan: вы получите каждое сканирование с деталями пачками каждые несколько минут.

Получение вебхуков в Next.js и их проверка

Когда: вы хотите знать, когда код сканируется или изменяется, в своей базе данных, почти в реальном времени.

  1. Создайте вебхук на Account › Webhooks или через POST /webhooks. Скопируйте секрет (whsec_...) один раз в QRFLOW_WEBHOOK_SECRET.
  2. Читайте сырое тело как текст перед парсингом; подпись покрывает точные байты.
  3. Проверьте, затем переключайтесь по событию. Отвечайте 2xx быстро; медленную работу делайте после ответа или в очереди.
  4. Нажмите Test на вебхуке, чтобы получить подписанный ping и подтвердить подключение.
import { createHmac, timingSafeEqual } from "node:crypto";

function verify(raw: string, header: string, secret: string): boolean {
  const t = /t=(\d+)/.exec(header)?.[1], v1 = /v1=([a-f0-9]+)/.exec(header)?.[1];
  if (!t || !v1 || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = createHmac("sha256", secret).update(\`${t}.${raw}\`).digest("hex");
  return expected.length === v1.length && timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

export async function POST(req: Request) {
  const raw = await req.text();
  if (!verify(raw, req.headers.get("x-qrflow-signature") ?? "", process.env.QRFLOW_WEBHOOK_SECRET!)) {
    return new Response("bad signature", { status: 401 });
  }
  const evt = JSON.parse(raw) as { id: string; event: string; created_at: string; data: any };
  // evt.id is stable across retries: store it and skip duplicates.

  switch (evt.event) {
    case "scan":          // evt.data.scans[]: code_id, label, slug, scanned_at, device, country, city, referrer, browser, os, language
      break;
    case "code.created":  // evt.data.code, evt.data.source
    case "code.updated":  // evt.data.code, evt.data.changed[]
    case "code.deleted":  // evt.data.code { id, label, short_code, slug }
      break;
    case "ping":          // the Test button
      break;
  }
  return new Response(null, { status: 204 });
}
  • Локально откройте dev-сервер через туннель (cloudflared tunnel --url http://localhost:3000, или ngrok) и используйте этот https URL для вебхука, пока разрабатываете.
  • npm-пакет делает это за вас: import { parseWebhook } from "qrflow"\ проверяет и парсит одним вызовом (WebCrypto, поэтому работает и в Workers, и в Deno). Python-клиент включает verify_webhook.

Получение вебхуков в Python

Когда: Flask, FastAPI или Django принимают те же события.

import os, json
from flask import Flask, request, abort
from qrflow import verify_webhook   # https://qrflow.codes/sdk/qrflow.py

app = Flask(__name__)

@app.post("/qrflow")
def hook():
    raw = request.get_data()  # bytes, before any parsing
    if not verify_webhook(raw, request.headers.get("X-QRFLOW-Signature", ""), os.environ["QRFLOW_WEBHOOK_SECRET"]):
        abort(401)
    evt = json.loads(raw)
    if evt["event"] == "scan":
        for s in evt["data"]["scans"]:
            print(s["code_id"], s["scanned_at"], s["country"], s["device"])
    return "", 204

Тысячи кодов из CSV

Когда: код на каждый SKU, место, инвентарный номер, рассылку.

import { parse } from "csv-parse/sync";
import { readFileSync } from "node:fs";

const rows = parse(readFileSync("skus.csv"), { columns: true }) as Array<{ sku: string; url: string }>;
const out: Array<{ sku: string; id: string; short_url: string }> = [];

for (let i = 0; i < rows.length; i += 2000) {                 // Business: 2,000 per request
  const chunk = rows.slice(i, i + 2000);
  const { codes, rejected, remaining_this_month } = await qr.bulkCreate(
    chunk.map((r) => ({ destination: r.url, label: r.sku })),
  );
  codes.forEach((c, j) => out.push({ sku: chunk[j].sku, id: c.id, short_url: c.short_url }));
  if (rejected.length) console.warn(rejected);                  // rows that were not web addresses
  console.log(remaining_this_month, "left this month");
}
  • Bulk создает только динамические url-коды, все с одинаковыми цветами. Коды возвращаются в том порядке, в котором вы их отправили, минус отклоненные строки; при сомнениях сопоставляйте по метке.
  • Вебхуки получают одно событие code.created на bulk-запрос с codes[] вместо одного на каждый код.

Позвольте пользователям подключать свой аккаунт QRFLOW (OAuth)

Когда: вы создаете продукт для других людей и хотите, чтобы коды попадали в их аккаунты QRFLOW, а не в ваш.

  1. Зарегистрируйте клиент один раз: POST https://qrflow.codes/api/oauth/register с client_name и redirect_uris. Вы получите client_id (и client_secret для конфиденциальных клиентов).
  2. Отправьте пользователя на /oauth/authorize с response_type=code, client_id, redirect_uri, scope, state и PKCE (code_challenge, code_challenge_method=S256).
  3. Обменяйте код на /api/oauth/token. Сохраните refresh token; access-токены живут час.
  4. Вызывайте /api/v1 с Authorization: Bearer <access_token>. Все работает точно так же, как с ключом, в рамках тарифа пользователя.
curl -X POST https://qrflow.codes/api/oauth/register -H "Content-Type: application/json" \
  -d '{ "client_name": "Acme Menus", "redirect_uris": ["https://app.example.com/oauth/qrflow"], "token_endpoint_auth_method": "none" }'
# { "client_id": "dyn_…", "redirect_uris": [...], "grant_types": ["authorization_code","refresh_token"], … }
https://qrflow.codes/oauth/authorize?response_type=code&client_id=dyn_…&redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth%2Fqrflow
  &scope=profile%20codes%3Aread%20codes%3Awrite%20analytics%3Aread&state=…&code_challenge=…&code_challenge_method=S256
  • Scopes — те же шесть, что и у API-ключей. Запрашивайте минимум, что вам нужно; экран согласия их перечисляет.
  • Если ваше приложение — чат-ассистент или агент, добавьте resource=https://qrflow.codes/mcp в authorize-запрос и общайтесь с MCP-сервером вместо этого; токен будет привязан к нему.

Zapier, Make, n8n: вообще без кода

Когда: вы хотите, чтобы сканирования или новые коды попадали в таблицу, Slack-канал или CRM.

  1. Создайте catch-hook триггер (Zapier: Webhooks by Zapier › Catch Hook; Make: Custom webhook; n8n: Webhook node) и скопируйте его https URL.
  2. На Account › Webhooks добавьте этот URL и выберите события. Нажмите Test; ping появится в инструменте и даст ему форму полезной нагрузки.
  3. Сопоставьте data.scans[] (для scan) или data.code (для code.*) с вашей таблицей, сообщением или записью.
  4. Чтобы создавать коды из этих инструментов, используйте их HTTP-модуль против POST /codes с заголовком Authorization. Храните ключ в хранилище учетных данных инструмента.
  • Эти инструменты не могут проверить подпись. URL, который они вам дают, невозможно угадать — это ваша защита; не публикуйте его нигде.

Vibe-кодинг

Промпты для вставки

Помощники по кодингу делают правильные вещи, когда им заранее объясняют правила. Эти промпты несут правила. Вставьте один, заполните скобки, и помощник прочитает Markdown-справочник, прежде чем написать строку кода.

Добавьте QR-коды в мое приложение

Claude, ChatGPT, Cursor, Codex, Windsurf, Copilot Chat: вставьте в чат

Add QR codes to this project using the QRFLOW.codes API.

Read https://qrflow.codes/llms-full.txt before writing code; it is the complete reference.

Rules:
- The API key is in the environment variable QRFLOW_KEY. It must only be used server-side (route handler, server action, edge function). Never expose it to the browser.
- Create dynamic codes: POST https://qrflow.codes/api/v1/codes with { "type": "url", "destination_data": { "url": ... }, "label": ... }.
- Save the returned code.id and code.short_url on my record. short_url is what gets printed or displayed.
- Show the image by proxying GET /codes/:id/image.svg through my server, or by encoding short_url with a QR library on the client.
- Handle errors from the JSON body: { "error", "message" }. Map 402 to "upgrade needed", 429 to a retry with the Retry-After header.

What I want: [describe the feature, e.g. "every event in my events table gets a QR code that opens its public page; show it on the event admin page with a download button"].

Обучите ваш репозиторий QRFLOW

Положите в CLAUDE.md, AGENTS.md, .cursorrules или .github/copilot-instructions.md

## QR codes (QRFLOW.codes)
- Docs: https://qrflow.codes/llms-full.txt (Markdown), https://qrflow.codes/api/v1/openapi.json (OpenAPI 3.1).
- Base URL https://qrflow.codes/api/v1, header Authorization: Bearer $QRFLOW_KEY. Server-side only.
- Codes are created with POST /codes { type: "url", destination_data: { url }, label }. Store code.id and code.short_url.
- Change the destination with PATCH /codes/:id { destination_data: { url } }. Never change slug/domain_id after printing.
- Image: GET /codes/:id/image.svg (needs the key). Prefer paused: true over DELETE when a print exists.
- Webhooks arrive as POST with X-QRFLOW-Signature (t=,v1=HMAC-SHA256 of "t.rawBody"); verify with the raw body.

В Lovable, Bolt, v0, Replit и других конструкторах приложений

Конструкторы с приоритетом фронтенда, которые дают вам бэкенд (Supabase, serverless-функции)

Integrate QRFLOW.codes QR codes. The API refuses browser calls, so create a backend function (Supabase Edge Function / serverless function) that holds the secret QRFLOW_KEY and calls POST https://qrflow.codes/api/v1/codes with { "type": "url", "destination_data": { "url": "<the page URL>" }, "label": "<name>" }. Return code.id and code.short_url to the UI and save them in the database. Render the QR in the UI by encoding short_url with a QR library; add a "Download for print" button that fetches /codes/:id/image.svg through the same backend function. Reference: https://qrflow.codes/llms-full.txt

Кастомный GPT, который управляет моими кодами

ChatGPT › Create a GPT › Actions

Import from URL: https://qrflow.codes/api/v1/openapi.json
Authentication: API Key › Bearer › paste a Business key with the scopes you want the GPT to have.
Then the GPT can list, create, re-point and report on your codes. For a no-setup version, add the MCP connector instead (Developer mode › Plugins › https://qrflow.codes/mcp).

Что сказать, когда коннектор подключен

Claude, ChatGPT, Claude Code с подключенным MCP-сервером QRFLOW

"Make a QR code for https://example.com/fall-menu, call it Fall menu, frame caption 'Scan for menu'."
"Which of my codes got the most scans this month? Show a breakdown by country for the top one."
"Point the 'Lobby poster' code at https://example.com/events/october."
"Name the 'Business card' code's link 'hi' on my domain."
"Pause every code with 'Summer' in the label."
"Make 40 codes, one per table, going to https://example.com/order?table=1 through 40."
"Show me the PNG of the 'Front door' code."

MCP-сервер

Использование из Claude, ChatGPT, Cursor и Claude Code

QRFLOW — это MCP-сервер по адресу https://qrflow.codes/mcp. Подключите его один раз, войдите, и затем говорите что-то вроде «сделай QR-код для нашей страницы осеннего меню, названный menu на моем домене», «перенаправь код постера в лобби на новую страницу» или «сколько сканирований было у флаера на прошлой неделе, по странам?». Помощник получает те же инструменты, что предлагает этот API, по тем же правилам, и коды попадают в ваш дашборд с mcp как источником.

Не разработчик? Простая версия с точными кликами для каждого помощника — на странице Создавайте QR-коды с вашим ИИ-ассистентом.

Подключение

Customize › Connectors › Add custom connector › вставьте адрес или нажмите Connect в листинге QRFLOW. Claude открывает вход в QRFLOW; нажмите Allow. Работает на любом тарифе.

https://qrflow.codes/mcp

Settings › Security and login › включите Developer mode, затем Settings › Plugins › + › вставьте адрес; войдите, когда попросят. Plus, Pro, Team, Enterprise и Edu.

https://qrflow.codes/mcp

Одна команда, затем /mcp для входа. Добавьте Business-ключ как заголовок, чтобы пропустить вход.

claude mcp add --transport http qrflow https://qrflow.codes/mcp
# or, with a key:
claude mcp add --transport http qrflow https://qrflow.codes/mcp --header "Authorization: Bearer $QRFLOW_KEY"

Cursor, Windsurf, VS Code, любой MCP-клиент

Добавьте HTTP-сервер по URL. OAuth-вход происходит в браузере; или передайте заголовок Authorization с ключом.

{
  "mcpServers": {
    "qrflow": { "type": "http", "url": "https://qrflow.codes/mcp" }
  }
}

Ваш собственный агент (Anthropic или OpenAI SDK)

Направьте MCP-коннектор или инструмент на URL с Business-ключом как bearer; браузерный поток не нужен.

// Anthropic Messages API, MCP connector
mcp_servers: [{ type: "url", url: "https://qrflow.codes/mcp", name: "qrflow", authorization_token: process.env.QRFLOW_KEY }]

Что умеет помощник

ИнструментЧто делаетОбласть
list_code_kindsКаждый вид кода с его полями и требуемым тарифом. Помощник вызывает это перед созданием чего-то необычного.profile
list_domainsВаши домены ссылок, домен по умолчанию и их id.domains:read
get_qr_imagePNG, который помощник может показать или сохранить, плюс SVG URL для печати.codes:read
get_accountКто вошел, тариф, лимиты.profile

Как это безопасно

  • Помощник всегда держит токен только для вашего аккаунта, выданный после того, как вы нажали Allow на странице QRFLOW. Отключите его в любой момент на Account › Connected apps.
  • Токены привязаны к MCP-серверу; их нельзя воспроизвести против REST API.
  • Каждая запись проходит ту же валидацию, что и дашборд: разрешенные адреса назначения, проверки тарифа, потолки добросовестного использования.
  • Деструктивные инструменты описывают себя аккуратно: delete_qr_code говорит модели предпочитать паузу, когда существует печать.
  • Документы обнаружения находятся по адресам /.well-known/oauth-authorization-server и /.well-known/oauth-protected-resource; регистрация по RFC 7591; только PKCE S256.

SDK и спецификация OpenAPI

  • TypeScript / JavaScript: npm install qrflow (npm). Ноль зависимостей, ESM и CommonJS, полные типы; работает в Node 18+, Bun, Deno и Workers. Повторяет 429 за вас и поставляет verifyWebhook / parseWebhook.
  • Python 3.9+, только стандартная библиотека: qrflow.py.
  • OpenAPI 3.1: /api/v1/openapi.json. Импортируйте в Postman или Insomnia, сгенерируйте клиент на любом языке или прикрепите к ChatGPT Action.
  • Оба клиента выбрасывают типизированную ошибку (QRFlowError с status, code, message, retryAfter) и поставляют верификатор вебхуков. Однофайловый TypeScript-исходник все еще находится по адресу /sdk/qrflow.ts, если вы предпочитаете вендорить его.
TypeScriptPythonВызовы
me()me()GET /me
catalog()catalog()GET /catalog
listCodes({ limit, q })list_codes(limit, q)GET /codes
getCode(id)get_code(id)GET /codes/:id
createCode(input)create_code(**fields)POST /codes
updateCode(id, patch)update_code(id, **patch)PATCH /codes/:id
deleteCode(id)delete_code(id)DELETE /codes/:id
makeDynamic(id)make_dynamic(id)POST /codes/:id/dynamic
scans(id, { from, to, group })scans(id, from_, to, group)GET /codes/:id/scans
bulkCreate(rows, colors)bulk_create(rows, **colors)POST /codes/bulk
domains()domains()GET /domains
listWebhooks() / createWebhook() / testWebhook(id) / deleteWebhook(id)list_webhooks() / create_webhook() / test_webhook(id) / delete_webhook(id)/webhooks
imageUrl(id, size)image_url(id, size)Адрес изображения (получите его с ключом)
verifyWebhook(raw, header, secret)verify_webhook(raw, header, secret)Проверка подписи для доставок

Справочник конечных точек

Базовый URL https://qrflow.codes/api/v1. Тела запросов и ответы — в формате JSON. Даты — ISO 8601 в UTC. При PATCH отправляйте только изменяемые поля.

GETprofile

Тарифный план, функциональные флаги и лимиты, действующие для этой учётной записи, а также области действия ключа.

curl https://qrflow.codes/api/v1/me \
  -H "Authorization: Bearer $QRFLOW_KEY"
{ "id": "…", "email": "ops@example.com", "plan": "business", "paid": true,
  "features": { "dynamic_codes": true, "custom_domain": true, "link_names": true, "gs1": true, "api_keys": true },
  "limits": { "saved_codes": 25000, "bulk_per_month": 10000, "bulk_per_request": 2000, "link_domains": 5, "requests_per_minute": 600 },
  "auth": "api_key", "scopes": ["codes:read", "codes:write"] }

GETpublic

Встроенные типы (url, wifi, vcard, email, phone, sms, text, location) и около 50 подтипов (Instagram, отзывы Google, Wi-Fi, магазин приложений и т. д.), каждый со своими полями и требуемым тарифным планом. Ключ не требуется.

curl https://qrflow.codes/api/v1/catalog

GETcodes:read

Сначала новые.?limit= до 100,?q= ищет по меткам.

curl "https://qrflow.codes/api/v1/codes?limit=20&q=menu" \
  -H "Authorization: Bearer $QRFLOW_KEY"

POSTcodes:write

Те же правила, что и при сохранении на сайте: коды url, phone, email, sms и location являются динамическими на платных тарифах; Wi-Fi, vCard и text содержат своё содержимое в шаблоне. Укажите идентификатор подтипа в destination_data.subtype, чтобы создать, например, код отзыва Google. Необязательный domain_id выбирает, с каким из ваших доменов ссылок будет печататься код (GET /domains выводит их список).

curl -X POST https://qrflow.codes/api/v1/codes \
  -H "Authorization: Bearer $QRFLOW_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "type": "url", "destination_data": { "url": "https://example.com/menu" }, "label": "Table tents", "frame_style": "caption-below", "frame_caption": "Scan for menu" }'
{ "code": { "id": "…", "label": "Table tents", "kind": "url", "dynamic": true, "short_code": "x7k2p9a",
  "short_url": "https://go.example.com/x7k2p9a", "scans": 0, "image_url": "https://qrflow.codes/api/v1/codes/…/image.svg", … } }

GETcodes:read

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

curl https://qrflow.codes/api/v1/codes/$ID \
  -H "Authorization: Bearer $QRFLOW_KEY"

PATCHcodes:write

Любые из: destination_data (только для динамических кодов, печать остаётся действительной), label, paused, expires_at (ISO или null), slug (имя ссылки на вашем домене), domain_id (с каким из ваших доменов ссылок печатается этот код; null = домен по умолчанию для учётной записи), fg_color, bg_color, frame_style, frame_caption, frame_caption2. Отправляйте только изменяемые поля.

curl -X PATCH https://qrflow.codes/api/v1/codes/$ID \
  -H "Authorization: Bearer $QRFLOW_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "destination_data": { "url": "https://example.com/menu-fall" }, "slug": "menu" }'

DELETEcodes:write

Удаляется навсегда, включая историю сканирований. Печатная ссылка динамического кода перестаёт открываться. Предпочтительнее использовать paused: true, если печать всё ещё используется.

curl -X DELETE https://qrflow.codes/api/v1/codes/$ID \
  -H "Authorization: Bearer $QRFLOW_KEY"
204 No Content

POSTcodes:write

Печатный шаблон меняется (теперь он кодирует короткую ссылку), поэтому после этого необходимо заново отрисовать изображение.

curl -X POST https://qrflow.codes/api/v1/codes/$ID/dynamic \
  -H "Authorization: Bearer $QRFLOW_KEY"

GETcodes:read

Готовый к печати SVG с рамкой и цветами.?size= задаёт ширину сетки модулей в пикселях; файл в любом случае масштабируется без потерь.

curl https://qrflow.codes/api/v1/codes/$ID/image.svg \
  -H "Authorization: Bearer $QRFLOW_KEY" -o code.svg

GETanalytics:read

?from= и?to= (даты в ISO, до 92 дней, по умолчанию последние 30) и?group= day, device, country, city, browser, os или referrer. Те же цифры, что и на странице аналитики.

curl "https://qrflow.codes/api/v1/codes/$ID/scans?from=2026-09-01&to=2026-09-21&group=day" \
  -H "Authorization: Bearer $QRFLOW_KEY"
{ "code_id": "…", "from": "…", "to": "…", "group": "day", "total": 412,
  "rows": [ { "key": "2026-09-01", "scans": 18 }, { "key": "2026-09-02", "scans": 25 }, … ] }

POSTcodes:write

До 2 000 URL-кодов за один вызов, все динамические. Учитывается в той же ежемесячной квоте массовых операций, что и страница Bulk (10 000 на тарифе Business). Строки, не являющиеся веб-адресами, возвращаются в rejected; остальные создаются.

curl -X POST https://qrflow.codes/api/v1/codes/bulk \
  -H "Authorization: Bearer $QRFLOW_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "rows": [ { "destination": "https://example.com/t/1", "label": "Table 1" }, { "destination": "https://example.com/t/2", "label": "Table 2" } ] }'
{ "codes": [ … ], "rejected": [], "remaining_this_month": 9998 }

GETdomains:read

Ваши подключённые домены, их статус и домен, с которым динамические коды печатаются по умолчанию (default_base). Передайте идентификатор домена как domain_id в коде, чтобы напечатать этот код с другим доменом.

curl https://qrflow.codes/api/v1/domains \
  -H "Authorization: Bearer $QRFLOW_KEY"

GETwebhooks:manage

Ваши вебхуки с их событиями, последним статусом и количеством сбоев.

curl https://qrflow.codes/api/v1/webhooks \
  -H "Authorization: Bearer $QRFLOW_KEY"

POSTwebhooks:manage

url должен быть https на публичном хосте; events — любое из scan, code.created, code.updated, code.deleted. Секрет подписи возвращается один раз.

curl -X POST https://qrflow.codes/api/v1/webhooks \
  -H "Authorization: Bearer $QRFLOW_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/hooks/qrflow", "events": ["scan", "code.updated"] }'
{ "webhook": { "id": "…", "url": "…", "events": ["scan", "code.updated"], "active": true, "secret": "whsec_…" } }

POSTwebhooks:manage

Отправляет подписанный ping сейчас и сообщает ответ.

curl -X POST https://qrflow.codes/api/v1/webhooks/$WEBHOOK_ID \
  -H "Authorization: Bearer $QRFLOW_KEY"

DELETEwebhooks:manage

Прекращает все доставки, включая поставленные в очередь повторные попытки.

curl -X DELETE https://qrflow.codes/api/v1/webhooks/$WEBHOOK_ID \
  -H "Authorization: Bearer $QRFLOW_KEY"
204 No Content

GETpublic

Идентификаторы рамок и что каждой из них требуется (подпись, вторая строка), сгруппированы как в настройщике. Ключ не требуется.

curl https://qrflow.codes/api/v1/frames

Объект Code

Каждая конечная точка, работающая с кодом, возвращает одну и ту же структуру. Игнорируйте неизвестные поля; со временем добавляются новые.

ПолеТипЗначение
iduuidСтабильный идентификатор. Используйте его во всех остальных вызовах.
labelstring | nullИмя на панели управления. До 120 символов. Можно искать с помощью?q=.
kindstringИдентификатор каталога: url, wifi, instagram, googlereview,... kind_label — человекочитаемое имя.
typestringКодировка: url, text, wifi, vcard, email, phone, sms, location.
destination_dataobjectОтправленные вами поля (плюс subtype для видов). destination — однострочное резюме.
dynamicbooleanTrue, когда сканирования проходят через QRFLOW и назначение может меняться. dynamic_capable показывает, может ли этот тип быть динамическим на платном тарифе.
short_codestringСемь символов, никогда не меняется.
short_urlstringЧто печатать для динамического кода. Включает ваш домен и slug, если заданы.
domain_iduuid | nullС каким доменом ссылок печатается этот код; null означает домен по умолчанию для учётной записи.
fg_color, bg_colorhexЦвета модуля и фона.
has_logobooleanЛоготип был добавлен на панели управления; image.svg включает его.
frame_style, frame_caption, frame_caption2string | nullИдентификатор рамки и подписи, как в настройщике.
scansintegerОбщее количество сканирований за всё время.
created_at, updated_atISO 8601UTC.
manage_urlurlСтраница кода на панели управления, для ссылки «Открыть в QRFLOW».
image_urlurlGET /codes/:id/image.svg. Требуется заголовок Authorization; это не публичный URL изображения.
svg_download_url, png_download_urlurlТот же SVG (рамка, цвета, логотип) и обычный PNG по подписанным ссылкам, действующим 24 часа без заголовка: для тегов <img>, скриптов и ассистентов, сохраняющих файл. download_expires_at показывает, когда они истекают; любое чтение кода возвращает свежие ссылки.

Другие структуры: Scans (code_id, from, to, group, total, rows[key, scans]), Domain (id, host, status, active, is_default, verified_at, grace_until), Webhook (id, url, events, active, last_status, last_delivery_at, consecutive_failures, плюс secret один раз), Me (id, email, plan, paid, features, limits, auth, scopes) и Error (error, message). В документе OpenAPI указаны типы всех свойств.

Business

Вебхуки

QRFLOW вызывает ваш https-URL, когда что-то происходит. Создайте его на Account › Webhooks или с помощью POST /webhooks; секрет подписи вы получаете один раз. До 10 на учётную запись.

СобытиеКогдаdata
scanПакетно: каждые несколько минут все новые сканирования с момента последней доставки, до 500 за вызов.count, from, to, scans[] с code_id, label, short_code, slug, scanned_at, device, country, city, referrer, browser, os, language
code.createdНемедленно из API и ассистентов; в течение нескольких минут с панели управления. Массовый запрос отправляет одно событие с bulk: true и codes[].code, source
code.updatedТа же периодичность. Охватывает назначение, метку, паузу, срок действия, имя ссылки, домен, цвета, рамку и преобразование в динамический.code, changed[] (имена изменённых полей)
code.deletedТа же периодичность.code: { id, label, short_code, slug }
pingКогда вы нажимаете Test.webhook_id, message

Что приходит

Каждая полезная нагрузка — это { id, event, created_at, data }. id стабилен при повторных попытках одной доставки, поэтому вы можете дедуплицировать по нему.

{
  "id": "9b1c6d2e-…",
  "event": "scan",
  "created_at": "2026-09-21T18:05:00.000Z",
  "data": {
    "count": 2,
    "from": "2026-09-21T18:00:00.000Z",
    "to": "2026-09-21T18:04:12.331Z",
    "scans": [
      { "code_id": "…", "label": "Table tents", "short_code": "x7k2p9a", "slug": "menu", "scanned_at": "2026-09-21T18:03:40.101Z",
        "device": "mobile", "country": "US", "city": "Las Vegas", "referrer": null, "browser": "Safari", "os": "iOS", "language": "en-US" },
      { "code_id": "…", "label": "Table tents", "short_code": "x7k2p9a", "slug": "menu", "scanned_at": "2026-09-21T18:04:12.331Z",
        "device": "mobile", "country": "MX", "city": "Tijuana", "referrer": null, "browser": "Chrome", "os": "Android", "language": "es-MX" }
    ]
  }
}
{
  "id": "2f0a…",
  "event": "code.updated",
  "created_at": "2026-09-21T18:06:00.000Z",
  "data": {
    "code": { "id": "…", "label": "Table tents", "kind": "url", "dynamic": true, "short_url": "https://go.example.com/menu", "scans": 412, "…": "…" },
    "changed": ["destination_data"]
  }
}
POST /your/endpoint HTTP/1.1
Content-Type: application/json
User-Agent: QRFLOW-Webhooks/1.0 (+https://qrflow.codes/developers)
X-QRFLOW-Event: scan
X-QRFLOW-Signature: t=1758477900,v1=5f1c…e9

Проверка подписи

X-QRFLOW-Signature: t=<unix seconds>,v1=<hex>. Вычислите HMAC-SHA256 от ${t}.${rawBody} с вашим секретом и сравните с v1 за постоянное время; отклоняйте, если t старше пяти минут. Используйте полученные необработанные байты, никогда не повторно сериализованный объект. Рабочие приёмники для Next.js и Python есть в рецептах, и оба SDK включают вспомогательную функцию.

Правила доставки

  • Ответьте любым 2xx в течение 8 секунд. Выполняйте работу после ответа.
  • Всё остальное повторяется через 1, 5, 15, 60, 240 и 720 минут.
  • Двадцать последовательных сбоев отключают вебхук и отправляют письмо владельцу учётной записи. Включите его снова, когда приёмник исправлен; поставленные в очередь повторные попытки возобновятся.
  • URL должны быть https на публичном хосте. localhost, частные диапазоны и сам qrflow.codes отклоняются. Используйте туннель во время разработки.
  • Нажмите Test, чтобы получить подписанный ping и увидеть статус, которым ответил ваш сервер.

Ошибки

Каждая ошибка — это { "error": "<code>", "message": "<what to do>" } со статусом ниже. Сообщение написано для человека; покажите его.

СтатусerrorЗначение

Симптом, причина, решение

Устранение неполадок

401 invalid_token при каждом вызове

ПочемуЗаголовок неверный или ключ не активен.

РешениеОтправьте точно Authorization: Bearer qrf_live_… (пробел, а не двоеточие). Проверьте, что ключ не был отозван в Account › API keys. Если вы скопировали его из чата или документа, обратите внимание на завершающую точку или типографскую кавычку.

401 на /api/v1 с токеном, который работает на MCP-сервере

ПочемуТокены, выпущенные для https://qrflow.codes/mcp, привязаны к нему.

РешениеИспользуйте API-ключ для REST или запустите второй OAuth-поток без resource=, чтобы получить токен для REST API.

402 upgrade_required при создании ключа или вебхука

ПочемуОбе функции доступны на тарифе Business.

РешениеОбновите тариф на /pricing или используйте MCP-сервер, который работает на любом плане через вход в систему.

402 на POST /codes из OAuth-приложения

ПочемуТарифный план пользователя не включает то, что запросило приложение (динамический код, домен).

РешениеСначала прочитайте GET /me features и адаптируйтесь: создайте код в любом случае (на Free он будет статическим) или сообщите пользователю, что требуется для тарифа.

403 insufficient_scope

ПочемуОбласти действия фиксируются при создании ключа.

РешениеСоздайте новый ключ с нужными областями и отзовите старый. Для OAuth запросите область в authorize-запросе.

400 not_dynamic при PATCH destination_data

ПочемуКод статический: создан на Free или имеет тип Wi-Fi/vCard/text.

РешениеДля url/phone/email/sms/location на платном тарифе выполните POST /codes/:id/dynamic, затем заново скачайте и распечатайте (изображение меняется). Wi-Fi, vCard и text никогда не могут быть динамическими; вместо этого создайте url-код, открывающий страницу.

400 no_domain при установке slug

ПочемуИмена ссылок живут на вашем домене.

РешениеСначала подключите и подтвердите домен на странице Account. На qrflow.codes/q путь всегда равен short_code.

409 conflict на slug

ПочемуДругой ваш код уже использует это имя.

РешениеВыполните GET /codes?q=, чтобы найти его, или выберите другое имя. Имена уникальны для учётной записи, а не глобально.

Ошибка CORS в консоли браузера

ПочемуAPI принимает только вызовы сервер-к-серверу (и Canva). Это намеренно: ключ на веб-странице — это утёкший ключ.

РешениеПеренесите вызов в обработчик маршрута, серверное действие, edge-функцию или бэкенд и вызывайте его со страницы.

На изображении водяной знак QRFLOW

ПочемуУчётная запись на тарифе Free.

РешениеПлатные тарифы убирают его. Free предназначен для собственного генератора сайта.

short_url всё ещё показывает qrflow.codes/q/… после добавления моего домена

ПочемуДомен ещё не подтверждён или его CNAME неверен.

РешениеПроверьте статус на странице Account или через GET /domains (статус должен быть verified). Существующие коды переключатся автоматически после подтверждения.

image_url даёт 401 в теге <img>

ПочемуТребуется заголовок Authorization, который тег <img> отправить не может.

РешениеИспользуйте svg_download_url или png_download_url из того же объекта Code: подписанные ссылки, действующие 24 часа без заголовка. Для постоянного доступа проксируйте image_url через свой сервер (см. рецепт Next.js) или закодируйте short_url самостоятельно.

Мне нужен PNG, а не SVG

ПочемуSVG содержит рамку и логотип; PNG — это обычный код.

РешениеGET /codes/:id/image.png (bearer или подписанный png_download_url) возвращает PNG размером от 256 до 2048 px. Для PNG с рамкой конвертируйте SVG с помощью sharp или resvg (sharp(svgBuffer).png().toBuffer()).

Мой ассистент сказал, что конечная точка изображения отказала ему, и нарисовал код сам

ПочемуОн запросил image_url, который требует bearer.

РешениеКаждый код теперь содержит png_download_url и svg_download_url, и get_qr_image возвращает их; ассистент может скачать их без входа. Локально нарисованный код, кодирующий тот же short_url, по-прежнему работает и учитывает сканирования, но у него нет рамки и логотипа.

Вебхук никогда не приходит

ПочемуПравила URL или приёмник.

РешениеURL должен быть https на публичном хосте (без localhost, без частных IP, не qrflow.codes). Нажмите Test на вебхуке: результат покажет статус, которым ответил ваш сервер. События scan группируются и могут занимать до пяти минут; события code.* с панели управления также ставятся в очередь на несколько минут, тогда как записи из API и MCP доставляются сразу.

Подпись никогда не проверяется

ПочемуВы подписали повторно сериализованное тело. FixVerify выполняется по точным исходным байтам, которые вы получили, до разбора JSON. В Express используйте express.raw({ type: 'application/json' }) на этом маршруте; в Next.js App Router используйте await req.text(); в Flask request.get_data(). Затем вычислите HMAC-SHA256 от ${t}.${raw}\.

Вебхук сам отключился

ПочемуДвадцать последовательных сбоев.

ИсправлениеИсправьте получатель, затем снова активируйте его (Аккаунт › Вебхуки, или удалите и создайте заново). Вам было отправлено письмо, когда это произошло. Поставленные в очередь повторные попытки возобновятся.

Дублирующиеся доставки вебхуков

ПочемуМедленный ответ 2xx (более 8 секунд) считается сбоем и повторяется.

ИсправлениеСначала отвечайте, потом обрабатывайте. Дедуплицируйте по id в полезной нагрузке, который стабилен при повторных попытках.

429 rate_limited во время импорта

Почему600 запросов в минуту на ключ.

ИсправлениеИспользуйте POST /codes/bulk (2 000 кодов в одном запросе) вместо одного POST на код, или подождите Retry-After секунд.

Я удалил код, и напечатанный постер теперь показывает «Код не найден»

ПочемуУдаление необратимо и разрывает ссылку.

ИсправлениеОтмены нет. В следующий раз используйте PATCH { paused: true }; приостановленный код показывает дружелюбную страницу и может быть возобновлён.

Мой ключ перестал работать после понижения тарифа

ПочемуКлючи продолжают работать 30 дней после ухода с Business, затем отвечают 402.

ИсправлениеОформите подписку заново; ничего не было удалено, и те же ключи снова работают.

Что-то не из списка? hello@qrflow.codes, с точным запросом и JSON-ошибкой, которую вы получили. Аккаунты Business получают приоритет.

Лимиты и добросовестное использование

Лимит
Запросов в минуту на ключ600. 429 с Retry-After сверх этого.
Ключей на аккаунт10
Вебхуков на аккаунт10
Сохранённых кодов (добросовестное использование)1 000 Premium, 25 000 Business; API останавливается на удвоенном значении.
Массовые операции500/месяц (500 за запрос) Premium; 10 000/месяц (2 000 за запрос) Business.
Домены ссылок1 Premium, 5 Business
СканированияБез ограничений. Контрольное письмо при 100 000 сканированиях на код в месяц на Premium, 1 000 000 на Business; ничего не ограничивается.
Окно аналитики сканирований92 дня на запрос
Размер страницы списка100 (?limit=)
Метка / подписи / слаг120 / 60 / 40 символов
Таймаут и повторные попытки вебхука8 секунд; повторные попытки через 1, 5, 15, 60, 240 и 720 минут; отключение после 20 последовательных сбоев.
После ухода с BusinessКлючи и вебхуки продолжают работать 30 дней, затем 402. Ничего не удаляется.

Добросовестное использование — это то, на что рассчитан тариф. Ничего не ограничивается на этом числе; API останавливается на удвоенном значении, и вам сначала пишет человек. Более высокие объёмы: hello@qrflow.codes.

Безопасность — для вас и для тех, кто сканирует

Как QRFLOW защищает ваш аккаунт

  • Ключи показываются один раз и хранятся как SHA-256 хеши. Никто в QRFLOW не может прочитать ключ обратно; если вы его потеряли, создайте новый.
  • Каждый запрос ограничен аккаунтом, которому принадлежит ключ. id кода из другого аккаунта — это 404, никогда не утечка.
  • Области действия фиксированы для каждого ключа, поэтому ключ для панели отчётности не может создавать или удалять коды.
  • 600 запросов в минуту на ключ; сверх этого — чистый 429, а не замедление для всех.
  • Назначения находятся в белом списке: http, https, mailto, tel, sms, geo и короткий список схем приложений (whatsapp, tg, signal, spotify, магазины приложений). javascript:, data: и file: отклоняются при создании, поэтому скомпрометированная интеграция не может превратить ваши коды в атаку.
  • URL вебхуков должны быть https на публичных хостах; QRFLOW никогда не вызывает частные сети или сам себя. Каждая доставка подписана, и каждая полезная нагрузка имеет стабильный id.
  • OAuth-клиенты регистрируются с PKCE S256, и токены привязаны к серверу, для которого они выданы; токен для MCP-сервера не может быть воспроизведён на REST API.
  • Любой может отозвать ключ или отключить приложение на странице Аккаунта; эффект немедленный.

Что делать с вашей стороны

  • Переменные окружения, никогда исходный код. Если ключ попал в историю git, отзовите его.
  • Только на стороне сервера. API отклоняет браузерные источники, но ваши собственные конечные точки, которые его оборачивают, тоже нуждаются в аутентификации, иначе любой может создавать коды за ваш счёт.
  • Дайте каждой интеграции свой ключ с нужными областями действия, названный по интеграции. Отзыв одного тогда влияет на одну вещь.
  • Проверяйте подписи вебхуков и отклоняйте метки времени старше пяти минут.
  • Если данные ваших пользователей попадают в метки или назначения, помните, что QRFLOW их хранит; по возможности держите личные данные вне меток.

Что записывают сканирования, а что нет

  • Каждое перенаправление хранит тип устройства, страну, город, реферер, браузер, операционную систему и язык, полученные из запроса, и односторонний хеш кода + дня + IP + пользовательского агента, чтобы владелец мог подсчитать уникальных посетителей. Хеш нельзя превратить обратно в адрес.
  • На сканирующего человека не устанавливаются файлы cookie, и сам IP-адрес не хранится со сканированием. Известные боты и краулеры предпросмотра ссылок пропускаются.
  • Удаление кода удаляет его сканирования. Удаление аккаунта удаляет всё.
  • Полный текст: https://qrflow.codes/privacy и https://qrflow.codes/terms.

Версионирование и стабильность

API версионируется в пути: /api/v1. В рамках v1 мы добавляем поля, конечные точки, виды и события; мы ничего не удаляем и не переименовываем, и неизвестные поля в ответах должны игнорироваться вашим кодом.

Если изменение когда-либо должно сломать v1, оно выходит как /api/v2, и v1 продолжает работать как минимум двенадцать месяцев. Владельцам ключей отправляется письмо о прекращении поддержки за 90 дней.

MCP-сервер следует тому же правилу для своих инструментов: аргументы только добавляются, и каждый инструмент сохраняет своё имя.

Документ OpenAPI по адресу /api/v1/openapi.json и Markdown по адресу /llms-full.txt генерируются из кода, который обслуживает API, поэтому они описывают то, что работает сегодня.

Вопросы разработчиков

Нужно ли платить за использование QRFLOW API?

Ключи API входят в план Business, $29 в месяц, помесячно. MCP-сервер (Claude, ChatGPT, Cursor, Claude Code) и OAuth для вашего собственного приложения работают на каждом плане через вход в систему, и то, что они могут создавать, следует плану. GET /catalog, GET /frames и /preview.svg не требуют ключа вообще.

Могу ли я бесплатно генерировать QR-коды через API?

Не с ключом. Для простого статического изображения бесплатный генератор на qrflow.codes или любая библиотека QR с открытым исходным кодом справится. API предназначен для динамических кодов, вашего собственного домена, аналитики, массовых операций и вебхуков — это то, для чего нужен платный аккаунт.

Могу ли я вызывать API из браузера?

Нет. Он отклоняет браузерные источники, чтобы ключ никогда не попал на веб-страницу. Вызывайте его из обработчика маршрута, серверного действия, edge-функции или бэкенда, и вызывайте это со своей страницы.

Какие форматы изображений я получаю?

SVG с вашими цветами, рамкой, подписями и логотипом (GET /codes/:id/image.svg, номинально от 256 до 4096 px) и обычный PNG (GET /codes/:id/image.png, от 256 до 2048 px). Оба принимают bearer или подписанные svg_download_url / png_download_url, которые несёт каждый объект Code и которые работают 24 часа без заголовка. Инструмент MCP get_qr_image возвращает PNG встроенно плюс обе ссылки.

Могу ли я изменить QR-код после печати?

Да, если он динамический (url, phone, email, sms, location на платном плане). PATCH /codes/:id с новым destination_data; картинка не меняется, следующее сканирование ведёт в новое место. Wi-Fi, vCard и текстовые коды несут своё содержимое в картинке и не могут быть изменены.

В чём разница между short_url и назначением?

short_url — это ссылка внутри картинки (go.example.com/menu). Назначение — это то, куда эта ссылка перенаправляет (https://example.com/menu-fall). Вы печатаете short_url один раз и меняете назначение сколько угодно.

Могут ли коды использовать мой собственный домен?

Да. Premium подключает 1 домен, Business 5; вы добавляете CNAME и подтверждаете на странице Аккаунта. Business выбирает домен для каждого кода с domain_id. Имена ссылок (слаг) создают читаемые пути на нём.

Что записывает сканирование о сканирующем человеке?

Тип устройства, страну, город, реферер, браузер, операционную систему и язык из запроса, плюс односторонний ежедневный хеш для подсчёта уникальных посетителей. Без файлов cookie, и IP-адрес не хранится. Достаточно для графика, недостаточно для идентификации кого-либо. Подробности: https://qrflow.codes/privacy#scans

Есть ли пакет npm или PyPI?

npm: npm install qrflow\ (https://www.npmjs.com/package/qrflow), без зависимостей, ESM и CommonJS, полные типы TypeScript, работает в Node 18+, Bun, Deno и Workers; он оборачивает каждую конечную точку, повторяет 429 и включает verifyWebhook/parseWebhook. Python: однофайловый клиент по адресу https://qrflow.codes/sdk/qrflow.py (только стандартная библиотека) с verify_webhook; пакет PyPI последует.

Работает ли это с Claude, ChatGPT, Cursor и Claude Code?

Да. QRFLOW — это MCP-сервер по адресу https://qrflow.codes/mcp. Добавьте его как коннектор, войдите один раз и спрашивайте простыми словами. Одиннадцать инструментов покрывают создание, редактирование, приостановку, именование, массовые операции, аналитику, изображения и домены.

Могут ли мои пользователи подключать свои аккаунты QRFLOW к моему приложению?

Да, с OAuth 2.0. Зарегистрируйте клиент по адресу /api/oauth/register (аккаунт не нужен), отправляйте пользователей на /oauth/authorize с PKCE и вызывайте API с их токеном. Коды попадают в их аккаунт под их планом.

Как мне тестировать вебхуки на localhost?

Откройте ваш dev-сервер через туннель (cloudflared или ngrok) и используйте его https-адрес как URL вебхука, затем нажмите Тест на Аккаунт › Вебхуки, чтобы получить подписанный ping. URL вебхуков должны быть публичными https; localhost и частные адреса отклоняются.

Что произойдёт с моей интеграцией, если я отменю Business?

Ключи и вебхуки продолжают работать 30 дней, затем отвечают 402. Коды, сканирования и домены остаются в аккаунте. Повторная подписка включает всё обратно с теми же ключами.

Как мне сделать код Google review, Instagram, Wi-Fi или PDF через API?

GET /catalog перечисляет каждый вид с его полями. Затем POST /codes с типом и полями вида, добавляя subtype для видов: { type: 'url', destination_data: { subtype: 'googlereview', placeId: 'ChIJ…' } }, { type: 'wifi', destination_data: { ssid, password, encryption: 'WPA' } }, { type: 'url', destination_data: { subtype: 'instagram', handle: 'acme' } }.

Может ли API загрузить логотип на код?

Пока нет. Добавьте логотип в панели управления; image.svg включает его, и has_logo сообщает вам, что он там. Цвета, рамки и подписи настраиваются через API.

Стабилен ли API?

v1 только добавляет; он никогда не удаляет и не переименовывает. Ломающее изменение вышло бы как v2 с сохранением v1 как минимум двенадцать месяцев и уведомлением по электронной почте за 90 дней.

Для агентов, инструментов и ассистентов, читающих это

Машиночитаемое

Всё на этой странице существует в форме, которую программное обеспечение может получить. Всё это генерируется из кода, который обслуживает API, поэтому оно никогда не устаревает.

URLЧто это
llms-full.txthttps://qrflow.codes/llms-full.txtВесь этот справочник в формате Markdown: концепции, каждая конечная точка, каждый MCP-инструмент, рецепты, устранение неполадок, FAQ. Сгенерировано из того же источника, что и эта страница.
developers.mdhttps://qrflow.codes/developers.mdТот же документ, для инструментов, которые загружают .md.
llms.txthttps://qrflow.codes/llms.txtИндекс сайта для ассистентов, указывающий сюда.
API на одной страницеhttps://qrflow.codes/qr-code-apiЧто делает API, когда клиентская библиотека — лучшее решение, и сколько это стоит. Краткая версия этого справочника для принятия решения, а не для разработки.
openapi.jsonhttps://qrflow.codes/api/v1/openapi.jsonOpenAPI 3.1. Импортируйте в Postman, Insomnia, генератор кода или ChatGPT Action.
MCP-серверhttps://qrflow.codes/mcpStreamable HTTP, OAuth с динамической регистрацией или Business-ключом в качестве bearer.
server.jsonhttps://qrflow.codes/.well-known/mcp/server.jsonМанифест реестра MCP.
OAuth discoveryhttps://qrflow.codes/.well-known/oauth-authorization-serverМетаданные RFC 8414; документ защищённого ресурса находится рядом.
npm-пакетhttps://www.npmjs.com/package/qrflownpm install qrflow. Типизированный клиент, ноль зависимостей, проверка вебхуков. Python-клиент в одном файле на https://qrflow.codes/sdk/qrflow.py.
GitHubhttps://github.com/nativecodeapps/qrflow-sdkКлиенты, снимок OpenAPI и запускаемые примеры для вебхуков Next.js, Workers, Express, FastAPI и Flask. Приветствуются вопросы и PR.

Вопросы, идеи, вид кода, который нам стоит добавить: hello@qrflow.codes. Условия: /terms. Конфиденциальность: /privacy.