Документация Static QR API
Создайте ключ, вызовите POST /v1/generate с бэкенда, используйте SVG на сайте. Пошаговая инструкция ниже.
Подключение Static QR API
Полный путь: создайте ключ в WebQR, вызовите API со своего бэкенда, возьмите SVG из ответа и используйте на своём сайте. API stateless — WebQR ваши QR не хранит.
Пошаговая интеграция
Идите по шагам по порядку. SDK не нужен — HTTPS и JSON только с вашего сервера. Не кладите API-ключ в JavaScript браузера и не вшивайте в приложение.
-
Аккаунт и тариф
Войдите в WebQR на тарифе с доступом к Static QR API. Сравните включённые генерации в месяц и лимиты ключей на странице тарифов.
-
Создайте API-ключ
В кабинете откройте API-ключи, создайте ключ и сразу скопируйте секрет (показывается один раз). При желании ограничьте IP и включите обязательную подпись запросов для продакшена.
-
Сохраните ключ на сервере
Положите секрет в переменные окружения или менеджер секретов. Все вызовы — только с бэкенда. Не отдавайте ключ на фронт и не вшивайте в мобильное приложение.
-
Вызовите POST /v1/generate
Заголовки: X-API-Key и Content-Type: application/json. Тело: обязательная строка data (URL или текст) и опциональный объект design. Примеры ниже — подставьте свой ключ вместо образца.
https://api.webqr.io/v1/generatecurl -X POST https://api.webqr.io/v1/generate \ -H "Content-Type: application/json" \ -H "X-API-Key: wq_xxxxxxxxxx_your_secret" \ -d '{ "data": "https://webqr.io", "design": { "size": 512, "color": "#000000", "backgroundColor": "#FFFFFF", "styleType": "a7k2m9", "eyeType": "r2s4t6", "showColorGradient": false } }'<?php $ch = curl_init('https://api.webqr.io/v1/generate'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'X-API-Key: wq_xxxxxxxxxx_your_secret' ], CURLOPT_POSTFIELDS => '{ "data": "https://webqr.io", "design": { "size": 512, "color": "#000000", "backgroundColor": "#FFFFFF", "styleType": "a7k2m9", "eyeType": "r2s4t6", "showColorGradient": false } }', ]); echo curl_exec($ch);const res = await fetch('https://api.webqr.io/v1/generate', { method: 'POST', headers: { "Content-Type": "application/json", "X-API-Key": "wq_xxxxxxxxxx_your_secret" }, body: JSON.stringify({ "data": "https://webqr.io", "design": { "size": 512, "color": "#000000", "backgroundColor": "#FFFFFF", "styleType": "a7k2m9", "eyeType": "r2s4t6", "showColorGradient": false } }), }); const data = await res.json(); console.log(data);import requests r = requests.post( "https://api.webqr.io/v1/generate", headers={ "Content-Type": "application/json", "X-API-Key": "wq_xxxxxxxxxx_your_secret" }, json={ "data": "https://webqr.io", "design": { "size": 512, "color": "#000000", "backgroundColor": "#FFFFFF", "styleType": "a7k2m9", "eyeType": "r2s4t6", "showColorGradient": false } }, ) print(r.json()) -
Заберите SVG из ответа
При HTTP 200 возьмите data.qr_code (разметка SVG) и data.format ("svg"). В usage — счётчики квоты по этому запросу. При ошибках смотрите HTTP-статус и error.code, если он есть.
-
Используйте SVG на своём сайте
Сохраните файл, выложите на CDN, вставьте inline, приложите к письму или отправьте в печать. WebQR результат не хранит — хранение и id у вас.
-
Следите за квотой и биллингом
GET /v1/usage отдаёт счётчики без расхода квоты. Лимиты тарифа — в разделе Limits; если можете выйти за включённые генерации, подключите overage-биллинг в кабинете.
-
Дизайн, безопасность, ошибки
Дальше — поля дизайна, защита ключа и обработка ошибок. Чеклист для продакшена:
- В проде ограничьте ключ по IP allowlist, если у серверов стабильный исходящий IP.
- Включите обязательную подпись запросов (HMAC) для ключей вне закрытой сети.
- При 429 учитывайте Retry-After, если есть; при 402 сначала проверьте биллинг или потолок трат.
Скачать
- Скачать OpenAPI (YAML) Спецификация API в YAML — импорт в Postman, Insomnia или генераторы кода.
- Скачать коллекцию Postman Готовые запросы для Postman или Insomnia — после импорта укажите apiBase и apiKey.
POST /generate
Справка по POST /v1/generate: авторизация, URL, заголовки и верхний уровень тела. Полные примеры curl/PHP/JS/Python — в Инструкции.
Авторизация
ApiKeyAuth
Передавайте секрет в X-API-Key в каждом запросе. Если для ключа включена подпись — также X-WebQR-Timestamp и X-WebQR-Signature.
Метод запроса
URL запроса
Заголовки
| Параметр | Тип | Описание |
|---|---|---|
|
X-API-Key
Обязательно
|
string | Секрет API-ключа. |
|
Content-Type
Обязательно
|
string | Отправляйте application/json, иначе тело часто не парсится и всплывает валидация по data. |
|
X-WebQR-Timestamp
|
string | Unix timestamp (секунды). Нужен, если ключ требует подпись. |
|
X-WebQR-Signature
|
string | HMAC-SHA256 hex канонической строки. Нужен, если ключ требует подпись. |
Параметры
| Параметр | Тип | Описание |
|---|---|---|
|
data
Обязательно
|
string | Данные для кодирования (URL, текст, Wi‑Fi и т.д.). Макс. 1000 символов. |
|
design
|
object | Необязательный объект дизайна. Пропущенные поля — по умолчанию. |
Полный список полей design (styleType, глаза, рамки, логотипы, градиенты) — в разделе Параметры тела.
Успешный ответ (HTTP 200)
JSON: success, SVG в data.qr_code (format svg), content, нормализованный design и полный объект usage (счётчики, время сброса, текстовые подсказки).
{
"success": true,
"data": {
"qr_code": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\">…</svg>",
"format": "svg",
"content": "https://webqr.io",
"design": {
"size": 512,
"color": "#000000",
"backgroundColor": "#FFFFFF",
"styleType": "a7k2m9",
"eyeType": "r2s4t6",
"showColorGradient": false
}
},
"usage": {
"period": "2026-05",
"used_count": 42,
"included_limit": 200,
"paid_count": 0,
"charged_cents": 0,
"spending_cap_cents": 1000,
"included_quota_resets_at": "2026-06-01T00:00:00+00:00",
"what_counts_toward_limit": "Successful POST /v1/generate that returns SVG.",
"what_does_not_count": "GET /v1/usage, validation errors, and failed generations.",
"included_quota_note": "Included quota resets at the start of each calendar month.",
"overage_linear_floor_hint": "Overage is billed per 1000 paid generations (linear floor)."
}
}
Usage
Только чтение: счётчики за период, data.items пустой. Лимит генераций не тратит.
Авторизация
ApiKeyAuth
Передавайте секрет в X-API-Key в каждом запросе. Если для ключа включена подпись — также X-WebQR-Timestamp и X-WebQR-Signature.
Метод запроса
URL запроса
Заголовки
| Параметр | Тип | Описание |
|---|---|---|
|
X-API-Key
Обязательно
|
string | Секрет API-ключа. |
|
X-WebQR-Timestamp
|
string | Unix timestamp (секунды). Нужен, если ключ требует подпись. |
|
X-WebQR-Signature
|
string | HMAC-SHA256 hex канонической строки. Нужен, если ключ требует подпись. |
Если для ключа включена обязательная подпись, на GET /v1/usage тоже нужны X-WebQR-Timestamp и X-WebQR-Signature (пустое тело → SHA-256 от "").
Параметры
Нет query/body параметров. Авторизация только через заголовки.
Пример запроса
curl -X GET https://api.webqr.io/v1/usage \
-H "X-API-Key: wq_xxxxxxxxxx_your_secret"
<?php
$ch = curl_init('https://api.webqr.io/v1/usage');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: wq_xxxxxxxxxx_your_secret',
],
]);
echo curl_exec($ch);
const res = await fetch('https://api.webqr.io/v1/usage', {
headers: {
'X-API-Key': 'wq_xxxxxxxxxx_your_secret',
},
});
const data = await res.json();
console.log(data);
import requests
r = requests.get(
"https://api.webqr.io/v1/usage",
headers={
"X-API-Key": "wq_xxxxxxxxxx_your_secret",
},
)
print(r.json())
Снимок usage для аккаунта ключа. Квоту генераций не тратит. Объект `usage` такой же, как в ответе POST /v1/generate.
Параметры тела
Тело POST /v1/generate: обязательное data, опциональный design. Коды берите из разделов Модули, Глаза, Рамки и Логотипы.
| Параметр | Тип | Описание |
|---|---|---|
|
data
Обязательно
|
string | Данные для кодирования (URL, текст, Wi‑Fi и т.д.). Макс. 1000 символов. |
|
design
|
object | Необязательный объект дизайна. Пропущенные поля — по умолчанию. |
|
design.size
|
integer | Размер в пикселях (100–2048). |
|
design.color
|
string | Цвет модулей #RRGGBB. |
|
design.backgroundColor
|
string | Цвет фона #RRGGBB. |
|
design.borderColor
|
string | Цвет внешних глаз #RRGGBB. |
|
design.centerColor
|
string | Цвет внутренних глаз #RRGGBB. |
|
design.markerOutColor
|
string | Алиас borderColor. |
|
design.markerInColor
|
string | Алиас centerColor. |
|
design.styleType
|
string | Код формы модулей (см. Коды модулей). |
|
design.eyeType
|
string | Код внешних глаз (см. Внешние глаза). |
|
design.eyeInnerType
|
string | Код внутренних глаз (см. Внутренние глаза). |
|
design.showColorGradient
|
boolean | Градиент на модулях. |
|
design.unifiedGradient
|
boolean | Один градиент на модули и глаза. |
|
design.showAllColorGradient
|
boolean | Алиас unifiedGradient. |
|
design.showEyeGradient
|
boolean | Градиент на глазах. |
|
design.styleColorGradient
|
string | Направление градиента модулей. |
|
design.eyeGradientStyle
|
string | Направление градиента глаз. |
|
design.fromColor
|
string | Начало градиента модулей #RRGGBB. |
|
design.toColor
|
string | Конец градиента модулей #RRGGBB. |
|
design.eyeFromColor
|
string | Начало градиента глаз #RRGGBB. |
|
design.eyeToColor
|
string | Конец градиента глаз #RRGGBB. |
|
design.transparent
|
boolean | Прозрачный фон. |
|
design.title
|
string | Метаданные title (макс. 100). |
|
design.frameType
|
string | Код рамки из раздела Frames. Не передавайте поле или оставьте пустым, если рамка не нужна. |
|
design.frameColor
|
string | Цвет рамки #RRGGBB. |
|
design.showFrameGradient
|
boolean | Градиент рамки. |
|
design.frameGradientFrom
|
string | Начало градиента рамки #RRGGBB. |
|
design.frameGradientTo
|
string | Конец градиента рамки #RRGGBB. |
|
design.frameGradientStyle
|
string | Направление градиента рамки. |
|
design.frameGradientTextColor
|
string | Цвет подписи при градиенте рамки. |
|
design.textColor
|
string | Цвет текста рамки #RRGGBB. |
|
design.textUnderQr
|
string | Подпись под QR (макс. 40; с рамками). |
|
design.roundedCorners
|
boolean | Скругление углов холста QR. |
|
design.cornerRadius
|
integer | Радиус скругления в px (0–120). |
|
design.logo
|
string | Рекомендуется: код пресета (Lxxxxx) или публичный HTTPS URL. Advanced: data URI и часть внутренних storage-путей; для интеграций предпочтителен HTTPS. |
|
design.selectedLogo
|
string | Код пресета или HTTPS URL. |
|
design.logoBackgroundEnabled
|
boolean | Подложка под логотипом. |
|
design.loadLogoBackgroundOut
|
string | Цвет подложки логотипа #RRGGBB (пресеты Lxxxxx). |
|
design.loadLogoBackgroundIn
|
string | Цвет иконки логотипа #RRGGBB (пресеты Lxxxxx). |
Формат ответа только SVG (data.format: "svg"). PNG/PDF через этот API недоступны.
Коды модулей (design.styleType)
Используйте строку кода в design.styleType, eyeType, eyeInnerType, frameType или logo.
Внешние искатели (design.eyeType)
Используйте строку кода в design.styleType, eyeType, eyeInnerType, frameType или logo.
Внутренние искатели (design.eyeInnerType)
Используйте строку кода в design.styleType, eyeType, eyeInnerType, frameType или logo.
Рамки (design.frameType)
n0f1r2 = без рамки (то же, что не передавать frameType или пустая строка). t7r8d9 — толстая скруглённая обводка без подписи. У остальных рамок подпись может быть в полосе; textUnderQr необязателен — иначе сервер подставляет подпись по умолчанию.
Готовые логотипы (design.logo)
Те же пресеты, что в конструкторе: передайте код (La1b2c…) в design.logo или design.selectedLogo. Для пресетов — loadLogoBackgroundOut и loadLogoBackgroundIn (#RRGGBB). Также https-URL и data:image/…; logoBackgroundEnabled — подложка под своим логотипом. Подробнее: docs/qr-logos.md в репозитории.
Поля логотипа
logo и selectedLogo — синонимы. Цвета loadLogoBackground* действуют только на пресеты Lxxxxx.
design.logodesign.selectedLogodesign.loadLogoBackgroundOutdesign.loadLogoBackgroundIndesign.logoBackgroundEnabled
Направления градиентов
Используйте эти имена в styleColorGradient и eyeGradientStyle.
horizontalverticaldiagonalinverse_diagonalradial
Лимиты API
Включённые генерации в месяц, число ключей и rate limit по тарифу. Цены продуктов — на странице тарифов.
По тарифам
Включённые успешные генерации в календарный месяц, активные ключи и rate limit по плану.
| Тариф | Включено / месяц | Активные ключи | Rate limit |
|---|---|---|---|
| Starter | 200 генераций | до 1 | 30/мин · burst 2/с |
| Premium | 5000 генераций | до 5 | 120/мин · burst 8/с |
| Business | 25000 генераций | до 15 | 300/мин · burst 15/с |
| Enterprise | 50000 генераций | до 30 | 600/мин · burst 25/с |
|
Нужно больше или индивидуальные условия? Свяжитесь с нами — подберём лимиты и условия под ваш кейс. |
|||
Квота обновляется в начале календарного месяца. Лимит на ключ — после авторизации. До ключа (нет/неверный) — лимит по IP.
Что считается и что нет
- Только успешный POST /v1/generate с SVG в ответе даёт +1 к used_count.
- Включённый лимит обновляется каждый календарный месяц; неиспользованное не переносится.
- GET /v1/usage квоту не тратит — для дашбордов и алертов.
- С ключом: лимит на ключ (в минуту + короткий burst). До ключа / неверный ключ: около 45 запросов в минуту с IP.
- API не складывает QR в библиотеку WebQR. SVG и свои id храните сами.
- Успешный ответ — только SVG; эндпоинтов PNG/PDF у Static QR API нет.
- После включённой квоты платный overage ≈ $2 за 1000 генераций, если включён в кабинете. Дефолтный spending cap ≈ $10/мес (настраивается, есть верхний предел).
Связанное
- Квота Что именно увеличивает used_count и как устроен объект usage.
- Биллинг API в кабинете Включить сверхквоту и лимит трат в кабинете.
- Тарифы и цены Цены тарифов и что входит в каждый план.
Как считается квота
В used_count идёт только успешный POST /v1/generate с SVG. GET /v1/usage квоту не тратит. Список полей ниже — как в объекте usage ответа.
- Одна успешная генерация = +1 used_count. Ошибки валидации и 4xx/5xx не считаются.
- GET /v1/usage — для дашбордов и алертов: те же счётчики, без списания.
- Если overage подключён и статус payment_failed — весь Static QR API заблокирован (включая included quota), пока не исправлена оплата.
- Строки-подсказки (what_counts_toward_limit и др.) — для людей; автоматику стройте по числам и error.code.
Поля объекта `usage` в ответах generate и usage:
periodused_countincluded_limitpaid_countcharged_centsspending_cap_centsincluded_quota_resets_atwhat_counts_toward_limitwhat_does_not_countincluded_quota_noteoverage_linear_floor_hint
Типичные HTTP-ошибки
Одного HTTP-статуса мало — форма JSON зависит от слоя. Шлюз (нет/неверный ключ, IP) часто отдаёт `{ "error": "…" }`. Квота и биллинг — `{ "success": false, "error": { "code", "message" } }`. Валидация — Laravel `{ "errors": {…} }` (часто с `message`). Сбои генерации могут быть `{ "success": false, "message" }` без `error.code`. Язык текста может быть EN или RU — для машинной логики опирайтесь на статус и `error.code`, если он есть.
| HTTP | error.code | Смысл |
|---|---|---|
| 401 | — | Нет заголовка X-API-Key. |
| 401 | — | Неверный, отозванный или просроченный ключ. |
| 401 | — | Подпись отсутствует/неверна при отправке заголовков, или неверна/просрочена при обязательной подписи. |
| 403 | — | IP клиента не в allowlist этого ключа. |
| 402 |
billing_payment_required
|
Overage-биллинг в статусе payment_failed — весь Static QR API заблокирован, включая включённую квоту, пока не исправлена оплата. |
| 402 |
free_limit_reached
|
Исчерпана месячная включённая квота, overage-биллинг не подключён. |
| 402 |
spending_cap_reached
|
Достигнут месячный потолок списаний за overage. |
| 422 | — | Ошибка валидации (типы, неизвестные коды стилей, HEX, длина полей, URL логотипа и т.д.). |
| 429 |
rate_limited
|
Слишком много запросов с IP (до ключа) или с ключа. Повторите позже; учитывайте Retry-After, если есть. |
| 500 | — | Сбой генерации — повторите позже. |
Формы JSON по статусам
Типичные тела ответов. Текст может отличаться; стабильный сигнал — `error.code`, когда он есть.
{
"error": "Invalid API key."
}
{
"success": false,
"error": {
"code": "billing_payment_required",
"message": "API billing payment failed or is overdue."
}
}
{
"message": "The data field is required.",
"errors": {
"data": [
"The data field is required."
]
}
}
{
"success": false,
"error": {
"code": "rate_limited",
"message": "Too many requests. Try again later."
}
}
{
"success": false,
"message": "QR code generation failed. Please try again later."
}
Безопасность в продакшене
Относитесь к API‑ключу как к паролю к квоте WebQR.
- Храните ключ только на сервере — не в браузере, мобильном приложении и не в публичных репозиториях.
- Вызывайте api.* с бэкенда. CORS для Static QR API в браузере не рассчитан — используйте сервер или Конструктор API в кабинете.
- Опционально ограничьте ключ IP серверов (или egress CDN). Пустой allowlist = любой IP.
- Опционально включите HMAC в кабинете. Тогда оба заголовка нужны на каждом маршруте — включая GET /v1/usage.
HMAC-подпись запросов (если включена для ключа)
Строка для подписи (UTF‑8)
1714412345
POST
/v1/generate
<sha256_hex_сырого_тела>
Для GET тело пустое. В последней строке — SHA-256 пустой строки:
1714412345
GET
/v1/usage
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Секрет HMAC: 40 символов после второго «_». Подпись — lowercase hex. Timestamp: Unix-секунды, допуск ±5 минут. SHA-256 тела — по точным байтам запроса. Строка path должна совпадать с путём URL (/v1/generate или /v1/usage).
Как посчитать подпись
Секрет — 40 символов после второго «_» в ключе. Подпись — lowercase hex HMAC-SHA256 канонической строки. Допуск по времени: ±5 минут.
# Build signature on your server, then attach headers to curl
TS=$(date +%s)
BODY='{"data":"https://webqr.io"}'
BODY_HASH=$(printf %s "$BODY" | openssl dgst -sha256 -hex | awk '{print $2}')
SECRET="${API_KEY##*_}" # 40 chars after the second underscore
CANON=$(printf '%s\nPOST\n/v1/generate\n%s' "$TS" "$BODY_HASH")
SIG=$(printf %s "$CANON" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $2}')
curl -X POST https://api.webqr.io/v1/generate \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-H "X-WebQR-Timestamp: $TS" \
-H "X-WebQR-Signature: $SIG" \
-d "$BODY"
<?php
$apiKey = getenv('WEBQR_API_KEY');
$secret = substr($apiKey, strrpos($apiKey, '_') + 1);
$ts = (string) time();
$body = json_encode(['data' => 'https://webqr.io'], JSON_UNESCAPED_SLASHES);
$canonical = $ts . "\nPOST\n/v1/generate\n" . hash('sha256', $body);
$signature = hash_hmac('sha256', $canonical, $secret);
$ch = curl_init('https://api.webqr.io/v1/generate');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-API-Key: ' . $apiKey,
'X-WebQR-Timestamp: ' . $ts,
'X-WebQR-Signature: ' . $signature,
],
CURLOPT_POSTFIELDS => $body,
]);
echo curl_exec($ch);
import crypto from 'node:crypto';
const apiKey = process.env.WEBQR_API_KEY;
const secret = apiKey.slice(apiKey.lastIndexOf('_') + 1);
const ts = String(Math.floor(Date.now() / 1000));
const body = JSON.stringify({ data: 'https://webqr.io' });
const bodyHash = crypto.createHash('sha256').update(body).digest('hex');
const canonical = `${ts}\nPOST\n/v1/generate\n${bodyHash}`;
const signature = crypto.createHmac('sha256', secret).update(canonical).digest('hex');
const res = await fetch('https://api.webqr.io/v1/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey,
'X-WebQR-Timestamp': ts,
'X-WebQR-Signature': signature,
},
body,
});
console.log(await res.json());
import hashlib, hmac, json, os, time, urllib.request
api_key = os.environ["WEBQR_API_KEY"]
secret = api_key.rsplit("_", 1)[-1]
ts = str(int(time.time()))
body = json.dumps({"data": "https://webqr.io"}, separators=(",", ":"))
body_hash = hashlib.sha256(body.encode()).hexdigest()
canonical = f"{ts}\nPOST\n/v1/generate\n{body_hash}"
signature = hmac.new(secret.encode(), canonical.encode(), hashlib.sha256).hexdigest()
req = urllib.request.Request("https://api.webqr.io/v1/generate", data=body.encode(), method="POST")
req.add_header("Content-Type", "application/json")
req.add_header("X-API-Key", api_key)
req.add_header("X-WebQR-Timestamp", ts)
req.add_header("X-WebQR-Signature", signature)
print(urllib.request.urlopen(req).read().decode())
Запрос с заголовками подписи
curl -X POST https://api.webqr.io/v1/generate \
-H "Content-Type: application/json" \
-H "X-API-Key: wq_xxxxxxxxxx_your_secret" \
-H "X-WebQR-Timestamp: 1714412345" \
-H "X-WebQR-Signature: 64_hex_chars_lowercase_hmac_sha256_placeholder_do_not_use_as_is" \
-d '{
"data": "https://webqr.io",
"design": {
"size": 512,
"color": "#000000",
"backgroundColor": "#FFFFFF",
"styleType": "a7k2m9",
"eyeType": "r2s4t6",
"showColorGradient": false
}
}'
<?php
$ch = curl_init('https://api.webqr.io/v1/generate');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-API-Key: wq_xxxxxxxxxx_your_secret',
'X-WebQR-Timestamp: 1714412345',
'X-WebQR-Signature: 64_hex_chars_lowercase_hmac_sha256_placeholder_do_not_use_as_is'
],
CURLOPT_POSTFIELDS => '{
"data": "https://webqr.io",
"design": {
"size": 512,
"color": "#000000",
"backgroundColor": "#FFFFFF",
"styleType": "a7k2m9",
"eyeType": "r2s4t6",
"showColorGradient": false
}
}',
]);
echo curl_exec($ch);
const res = await fetch('https://api.webqr.io/v1/generate', {
method: 'POST',
headers: {
"Content-Type": "application/json",
"X-API-Key": "wq_xxxxxxxxxx_your_secret",
"X-WebQR-Timestamp": "1714412345",
"X-WebQR-Signature": "64_hex_chars_lowercase_hmac_sha256_placeholder_do_not_use_as_is"
},
body: JSON.stringify({
"data": "https://webqr.io",
"design": {
"size": 512,
"color": "#000000",
"backgroundColor": "#FFFFFF",
"styleType": "a7k2m9",
"eyeType": "r2s4t6",
"showColorGradient": false
}
}),
});
const data = await res.json();
console.log(data);
import requests
r = requests.post(
"https://api.webqr.io/v1/generate",
headers={
"Content-Type": "application/json",
"X-API-Key": "wq_xxxxxxxxxx_your_secret",
"X-WebQR-Timestamp": "1714412345",
"X-WebQR-Signature": "64_hex_chars_lowercase_hmac_sha256_placeholder_do_not_use_as_is"
},
json={
"data": "https://webqr.io",
"design": {
"size": 512,
"color": "#000000",
"backgroundColor": "#FFFFFF",
"styleType": "a7k2m9",
"eyeType": "r2s4t6",
"showColorGradient": false
}
},
)
print(r.json())
При «Требовать подписанные запросы» оба заголовка обязательны на каждом запросе. Один без другого — отказ.
Частые вопросы
Да. Starter уже включает Static QR API: 200 успешных генераций за календарный месяц; Premium — 5000, Business — 25000. Отдельной API-подписки нет. Сверхквоту при необходимости включают в кабинете.
Включённые успешные генерации за календарный месяц: Starter 200, Premium 5000, Business 25000, Enterprise 50000. Неиспользованные не переносятся. Подробности — в разделе «Лимиты API» на этой странице.
После регистрации откройте «API-ключи» в кабинете, создайте ключ и сразу скопируйте секрет (он показывается один раз). Используйте только на бэкенде — не в браузерном JS и не в бинарнике мобильного приложения.
Нет. Ключ должен оставаться на сервере. Вызывайте POST /v1/generate с бэкенда, а клиенту отдавайте уже готовый SVG или ссылку на него.
В JSON приходит SVG в data.qr_code, те же content и design, плюс объект usage для квоты. API stateless: вызов сам по себе не попадает в библиотеку WebQR и не даёт постоянный id — SVG и связки храните у себя.
Только SVG (data.format = "svg"). Отдельного PNG/PDF-эндпоинта у Static QR API нет — конвертацию при необходимости делайте у себя.
Включите биллинг API в кабинете. Сверхквота — около $2 за 1000 успешных генераций, с месячным лимитом трат (по умолчанию около $10). Без включённого биллинга запросы сверх квоты отклоняются.
Да. API — для серверных интеграций, конструктор и кабинет — для ручной работы. Коды дизайна общие, но вызовы API сами по себе не создают записи в библиотеке.
Готовы генерировать QR с сервера?
Зарегистрируйтесь, создайте API-ключ в кабинете и пройдите инструкцию на этой странице.
Starter — бесплатно навсегда Без кредитной карты Отмена в любое время