REST API v1
Kverton API
Dynamic codes, statistics, rendering and webhooks from your own system. REST, JSON, key in a header. Static codes stay free in the browser — the API is for what cannot work without our server.
Getting started
- In team settings (Teams → team → API keys) create a key. It is shown once.
- Every request carries the header
Authorization: Bearer kv_… - Base URL:
https://kverton.cz/api/v1
- Format
- JSON in and out (Content-Type: application/json), UTF-8, timestamps in ISO 8601 (UTC). Version in the path (/v1) — a breaking change gets a new one.
- Errors
{"error":{"code":"quota","message":"…"}}· 401 · 403 · 404 · 422 · 429 · 500- Limits
- Daily quota by plan (per team; headers X-RateLimit-Quota and X-RateLimit-Remaining) and 120 calls per minute per key. 429 when exceeded.
- OpenAPI
- /api/v1/openapi.json — machine-readable description for client generators
https://kverton.cz/qr.svg · /qr.png
no key
Code image for <img>
Static codes are free — also as an image for e-mail templates, CMS or a PHP echo where there is no JavaScript and no key. The content is not stored; the rendered image is cached for a day (ETag).
| Parameter | |
|---|---|
| data * | code content, URL-encoded (rawurlencode), up to 2000 characters |
| size | png: side in px, 64–2000 (default 512); svg is a dimensionless vector |
| format | qr · datamatrix · azteccode · rmqr |
| ecl | L · M · Q · H |
| color, bg | hex without #, e.g. color=302B23&bg=FFFFFF — watch the contrast, the image is not verified by a decoder |
<img width="225" height="225" alt="QR"
src="https://kverton.cz/qr.png?size=225&data=bitcoin:bc1q…?amount=0.01%26label=Invoice">
<?php echo '<img src="https://kverton.cz/qr.svg?data=' . rawurlencode($uri) . '">'; ?>
Limit 60 images per minute per address. For dynamic codes, statistics and webhooks use the keyed API below.
How to compose data — every content kind
Rules
- Encode the whole value (
rawurlencodein PHP,encodeURIComponentin JS). Otherwise an&inside the content splits the parameters and spaces get lost — exactly what happens withbitcoin:…?amount=…&label=…. - Newlines (vCard, EPC, event) are
%0Ain the URL; encoding handles it when the string contains\n. - UTF-8 and diacritics are fine. Capacity: QR up to 2,000 characters (our limit), Data Matrix up to 1,500, rMQR up to 361.
- The same rules apply to
contentinPOST /api/v1/render(no URL encoding there — it travels as JSON). - The image endpoint does not verify the code with a decoder (the editor does). Keep contrast and the quiet zone; dark on light.
// PHP $data = "SPD*1.0*ACC:CZ6508000000192000145399*AM:450.00*CC:CZK*X-VS:2026041"; echo '<img src="https://kverton.cz/qr.png?size=300&data=' . rawurlencode($data) . '">'; // JavaScript const src = 'https://kverton.cz/qr.svg?data=' + encodeURIComponent(data);
| Kind | Shape | Example |
|---|---|---|
| Link | Absolute URL including https://. The Kverton reader checks redirects, Safe Browsing and domain age. |
https://example.cz/menu?stul=5
as it looks in the URL?data=https%3A%2F%2Fexample.cz%2Fmenu%3Fstul%3D5 |
| Czech payment (SPD) | Short Payment Descriptor: SPD*1.0* and *-separated fields: ACC IBAN (optionally +BIC), AM amount with a dot, CC currency, X-VS/X-SS/X-KS symbols, MSG message, DT due date YYYYMMDD, RN recipient. Czech banking apps read it directly. |
SPD*1.0*ACC:CZ6508000000192000145399*AM:450.00*CC:CZK*X-VS:2026041*MSG:Faktura 2026041*DT:20261015
as it looks in the URL?data=SPD%2A1.0%2AACC%3ACZ6508000000192000145399%2AAM%3A450.00%2ACC%3ACZK%2AX-VS%3A2026041%2AMSG%3AFaktura%202026041%2ADT%3A20261015 |
| European payment (EPC / SEPA) | EPC069-12: exactly 11 lines — BCD, version 002, encoding 1, SCT, BIC, beneficiary, IBAN, amount EUR12.50, purpose (empty), reference (empty), message. No line may be missing, even when empty. |
BCD
002
1
SCT
GIBACZPX
Firma s.r.o.
CZ6508000000192000145399
EUR12.50
Faktura 41
as it looks in the URL?data=BCD%0A002%0A1%0ASCT%0AGIBACZPX%0AFirma%20s.r.o.%0ACZ6508000000192000145399%0AEUR12.50%0A%0A%0AFaktura%2041 |
| Slovak payment (Pay by square) | A compressed binary payload — cannot be written by hand. Use the generator on kverton.sk (static code from the Slovak payment form). | — |
| Wi-Fi | WIFI:T:WPA;S:name;P:password;H:false;; — T WPA/WEP/nopass, H:true hidden network. Escape \; \, \: \\ in name and password. Two semicolons at the end. |
WIFI:T:WPA;S:Kavarna U Lipy;P:tajne-heslo;H:false;;
as it looks in the URL?data=WIFI%3AT%3AWPA%3BS%3AKavarna%20U%20Lipy%3BP%3Atajne-heslo%3BH%3Afalse%3B%3B |
| Contact (vCard 3.0) | The most widely supported contact format; phones offer to save it. N last;first, FN full name, TEL;TYPE=CELL, EMAIL, ORG, URL, ADR. Lines separated by newlines. |
BEGIN:VCARD
VERSION:3.0
N:Novák;Jan;;;
FN:Jan Novák
ORG:Firma s.r.o.
TEL;TYPE=CELL:+420777123456
EMAIL:jan@firma.cz
URL:https://firma.cz
END:VCARD
as it looks in the URL?data=BEGIN%3AVCARD%0AVERSION%3A3.0%0AN%3ANov%C3%A1k%3BJan%3B%3B%3B%0AFN%3AJan%20Nov%C3%A1k%0AORG%3AFirma%20s.r.o.%0ATEL%3BTYPE%3DCELL%3A%2B420777123456%0AEMAIL%3Ajan%40firma.cz%0AURL%3Ahttps%3A%2F%2Ffirma.cz%0AEND%3AVCARD |
| Contact (MeCard) | More compact than vCard — fits a smaller code. Fields N (Last,First), TEL, EMAIL, URL, ADR, NOTE; ends with ;;. |
MECARD:N:Novák,Jan;TEL:+420777123456;EMAIL:jan@firma.cz;URL:https://firma.cz;;
as it looks in the URL?data=MECARD%3AN%3ANov%C3%A1k%2CJan%3BTEL%3A%2B420777123456%3BEMAIL%3Ajan%40firma.cz%3BURL%3Ahttps%3A%2F%2Ffirma.cz%3B%3B |
mailto: with optional subject and body (encoded — spaces as %20). |
mailto:info@firma.cz?subject=Dotaz&body=Dobrý den,
as it looks in the URL?data=mailto%3Ainfo%40firma.cz%3Fsubject%3DDotaz%26body%3DDobr%C3%BD%20den%2C |
|
| Phone | tel: with the number in international form (+420…), no spaces. |
tel:+420777123456
as it looks in the URL?data=tel%3A%2B420777123456 |
| SMS | SMSTO:number:text — the most compatible form (Android and iPhone). Alternative sms:number?body=text. |
SMSTO:+420777123456:Text zprávy
as it looks in the URL?data=SMSTO%3A%2B420777123456%3AText%20zpr%C3%A1vy |
https://wa.me/number without +, optionally ?text= for a prefilled message. |
https://wa.me/420777123456?text=Dobrý den
as it looks in the URL?data=https%3A%2F%2Fwa.me%2F420777123456%3Ftext%3DDobr%C3%BD%20den |
|
| Telegram | https://t.me/user or a group link. |
https://t.me/uzivatel
as it looks in the URL?data=https%3A%2F%2Ft.me%2Fuzivatel |
| Location | geo:lat,lng; ?q=lat,lng(Label) adds a named pin. Opens the maps app. |
geo:50.0755,14.4378?q=50.0755,14.4378(Kavárna U Lípy)
as it looks in the URL?data=geo%3A50.0755%2C14.4378%3Fq%3D50.0755%2C14.4378%28Kav%C3%A1rna%20U%20L%C3%ADpy%29 |
| Calendar event | BEGIN:VEVENT…END:VEVENT (iCalendar): SUMMARY, DTSTART/DTEND in UTC (Z) or with TZID, LOCATION, DESCRIPTION. The reader adds the VCALENDAR wrapper. |
BEGIN:VEVENT
SUMMARY:Schůzka
DTSTART:20260930T090000Z
DTEND:20260930T100000Z
LOCATION:Praha
END:VEVENT
as it looks in the URL?data=BEGIN%3AVEVENT%0ASUMMARY%3ASch%C5%AFzka%0ADTSTART%3A20260930T090000Z%0ADTEND%3A20260930T100000Z%0ALOCATION%3APraha%0AEND%3AVEVENT |
| Two-factor key (TOTP) | otpauth://totp/Issuer:account?secret=BASE32&issuer=Issuer; optional digits, period, algorithm. The secret is sensitive — never print it in public places. |
otpauth://totp/Firma:jan@firma.cz?secret=JBSWY3DPEHPK3PXP&issuer=Firma&digits=6&period=30
as it looks in the URL?data=otpauth%3A%2F%2Ftotp%2FFirma%3Ajan%40firma.cz%3Fsecret%3DJBSWY3DPEHPK3PXP%26issuer%3DFirma%26digits%3D6%26period%3D30 |
| Crypto payment (BIP-21) | bitcoin:address?amount=0.01&label=…&message=…; Ethereum ethereum:0x…?value=…. Because of & the whole value must be encoded. |
bitcoin:bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq?amount=0.01&label=Faktura 41
as it looks in the URL?data=bitcoin%3Abc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq%3Famount%3D0.01%26label%3DFaktura%2041 |
| App link | A link to the App Store or Google Play; one code for both stores is a dynamic code with a device rule. |
https://apps.apple.com/app/id123456789 · https://play.google.com/store/apps/details?id=cz.firma.app
as it looks in the URL?data=https%3A%2F%2Fapps.apple.com%2Fapp%2Fid123456789%20%C2%B7%20https%3A%2F%2Fplay.google.com%2Fstore%2Fapps%2Fdetails%3Fid%3Dcz.firma.app |
| Video meeting | A Google Meet, Teams or Zoom link — a plain URL. |
https://meet.google.com/abc-defg-hij
as it looks in the URL?data=https%3A%2F%2Fmeet.google.com%2Fabc-defg-hij |
| GS1 Digital Linkformat=datamatrix | Packaging standard: https://id.gs1.org/01/GTIN/10/lot/17/expiry(YYMMDD)/21/serial. Printed on packaging as Data Matrix (format=datamatrix). |
https://id.gs1.org/01/09506000134352/10/ABC123/17/261231
as it looks in the URL?data=https%3A%2F%2Fid.gs1.org%2F01%2F09506000134352%2F10%2FABC123%2F17%2F261231 |
| Plain text | Anything meant only to be displayed. The reader offers to copy it. |
Libovolný text, včetně diakritiky a nových řádků.
as it looks in the URL?data=Libovoln%C3%BD%20text%2C%20v%C4%8Detn%C4%9B%20diakritiky%20a%20nov%C3%BDch%20%C5%99%C3%A1dk%C5%AF. |
Symbol format, error correction, size
- QR (default) — universal; all phones, payments, Wi-Fi.
- Data Matrix — smallest area per character; packaging, labels, electronics, GS1. Phones read it; banking apps do not.
- Aztec — no quiet zone; tickets and passes in tight frames.
- rMQR — rectangular QR for narrow strips (up to 361 characters); older readers don't know it, Kverton does.
- ecl: L 7% · M 15% (default) · Q 25% · H 30% of damaged modules can be repaired. Paper print: M; outdoors or with a logo: Q/H (bigger code).
- Print size: module ≥ 0.5 mm (a common version-3 QR is ≥ 2 cm), scanning from 1 m ≥ 5 cm. Request PNG of at least 300 px per 3 cm of print, otherwise use vector SVG.
/me
Scope: read
Tým, tarif a kvóta
Komu klíč patří, jaký tarif tým má a kolik volání dnes zbývá.
Response
{
"team": {
"id": 12,
"name": "Kavárna U Lípy",
"plan": "pro"
},
"limits": {
"dynamic_codes": 50,
"api_calls_per_day": 5000
},
"usage": {
"api_calls_today": 42,
"dynamic_codes": 7
}
}Samples: curl · PHP · JavaScript · Java
curl -X GET 'https://kverton.cz/api/v1/me' \ -H 'Authorization: Bearer kv_XXXXXXXX_…'
<?php
$ch = curl_init('https://kverton.cz/api/v1/me');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer kv_XXXXXXXX_…', 'Content-Type: application/json'],
]);
$data = json_decode((string) curl_exec($ch), true);
const res = await fetch('https://kverton.cz/api/v1/me', {
method: 'GET',
headers: { Authorization: 'Bearer kv_XXXXXXXX_…', 'Content-Type': 'application/json' },
});
const data = await res.json();
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://kverton.cz/api/v1/me"))
.header("Authorization", "Bearer kv_XXXXXXXX_…")
.header("Content-Type", "application/json")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
String json = res.body();
/codes
Scope: read
Seznam dynamických kódů
Stránkovaný seznam. Filtr podle skupiny a textu v popisku.
| Parameter | in | Type | |
|---|---|---|---|
| group | query | integer | ID skupiny |
| q | query | string | Hledání v popisku |
| page | query | integer | Stránka (od 1) |
| per_page | query | integer | Velikost stránky (1–200, výchozí 50) |
Response
{
"data": [
{
"id": 1234,
"slug": "a7k2m",
"short_url": "https://kvrt.net/a7k2m",
"label": "Podzimní menu",
"target_url": "https://eshop.cz/menu-podzim",
"active": true,
"expires_at": null,
"group_id": null,
"password_protected": false,
"utm": {
"source": "kverton",
"medium": "qr",
"campaign": null
},
"safety_state": "clear",
"created_at": "2026-09-01T10:00:00Z",
"last_scan_at": "2026-09-03T08:12:00Z"
}
],
"page": 1,
"per_page": 50,
"total": 1
}Samples: curl · PHP · JavaScript · Java
curl -X GET 'https://kverton.cz/api/v1/codes' \ -H 'Authorization: Bearer kv_XXXXXXXX_…'
<?php
$ch = curl_init('https://kverton.cz/api/v1/codes');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer kv_XXXXXXXX_…', 'Content-Type: application/json'],
]);
$data = json_decode((string) curl_exec($ch), true);
const res = await fetch('https://kverton.cz/api/v1/codes', {
method: 'GET',
headers: { Authorization: 'Bearer kv_XXXXXXXX_…', 'Content-Type': 'application/json' },
});
const data = await res.json();
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://kverton.cz/api/v1/codes"))
.header("Authorization", "Bearer kv_XXXXXXXX_…")
.header("Content-Type", "application/json")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
String json = res.body();
/codes
Scope: write
Založit dynamický kód
Vrátí kód včetně krátké adresy. Kód vytiskněte jako QR s obsahem short_url (SVG umí /render).
Request body
{
"label": "Podzimní menu",
"target_url": "https://eshop.cz/menu-podzim",
"expires_at": "2026-12-31",
"group_id": null,
"password": null,
"utm": {
"source": "kverton",
"medium": "qr",
"campaign": "podzim"
}
}Response
{
"id": 1234,
"slug": "a7k2m",
"short_url": "https://kvrt.net/a7k2m",
"label": "Podzimní menu",
"target_url": "https://eshop.cz/menu-podzim",
"active": true,
"expires_at": null,
"group_id": null,
"password_protected": false,
"utm": {
"source": "kverton",
"medium": "qr",
"campaign": null
},
"safety_state": "clear",
"created_at": "2026-09-01T10:00:00Z",
"last_scan_at": "2026-09-03T08:12:00Z"
}Samples: curl · PHP · JavaScript · Java
curl -X POST 'https://kverton.cz/api/v1/codes' \
-H 'Authorization: Bearer kv_XXXXXXXX_…' \
-H 'Content-Type: application/json' \
-d '{"label":"Podzimní menu","target_url":"https://eshop.cz/menu-podzim","expires_at":"2026-12-31","group_id":null,"password":null,"utm":{"source":"kverton","medium":"qr","campaign":"podzim"}}'
<?php
$ch = curl_init('https://kverton.cz/api/v1/codes');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer kv_XXXXXXXX_…', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(array (
'label' => 'Podzimní menu',
'target_url' => 'https://eshop.cz/menu-podzim',
'expires_at' => '2026-12-31',
'group_id' => NULL,
'password' => NULL,
'utm' =>
array (
'source' => 'kverton',
'medium' => 'qr',
'campaign' => 'podzim',
),
)),
]);
$data = json_decode((string) curl_exec($ch), true);
const res = await fetch('https://kverton.cz/api/v1/codes', {
method: 'POST',
headers: { Authorization: 'Bearer kv_XXXXXXXX_…', 'Content-Type': 'application/json' },
body: JSON.stringify({"label":"Podzimní menu","target_url":"https://eshop.cz/menu-podzim","expires_at":"2026-12-31","group_id":null,"password":null,"utm":{"source":"kverton","medium":"qr","campaign":"podzim"}}),
});
const data = await res.json();
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://kverton.cz/api/v1/codes"))
.header("Authorization", "Bearer kv_XXXXXXXX_…")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"label\":\"Podzimn\u00ed menu\",\"target_url\":\"https:\/\/eshop.cz\/menu-podzim\",\"expires_at\":\"2026-12-31\",\"group_id\":null,\"password\":null,\"utm\":{\"source\":\"kverton\",\"medium\":\"qr\",\"campaign\":\"podzim\"}}"))
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
String json = res.body();
/codes/{id}
Scope: read
Detail kódu
Jeden kód včetně pravidel přesměrování.
| Parameter | in | Type | |
|---|---|---|---|
| id * | path | integer | ID kódu |
Response
{
"id": 1234,
"slug": "a7k2m",
"short_url": "https://kvrt.net/a7k2m",
"label": "Podzimní menu",
"target_url": "https://eshop.cz/menu-podzim",
"active": true,
"expires_at": null,
"group_id": null,
"password_protected": false,
"utm": {
"source": "kverton",
"medium": "qr",
"campaign": null
},
"safety_state": "clear",
"created_at": "2026-09-01T10:00:00Z",
"last_scan_at": "2026-09-03T08:12:00Z",
"rules": [
{
"kind": "device",
"match": "ios",
"target_url": "https://apps.apple.com/app/x"
}
]
}Samples: curl · PHP · JavaScript · Java
curl -X GET 'https://kverton.cz/api/v1/codes/1234' \ -H 'Authorization: Bearer kv_XXXXXXXX_…'
<?php
$ch = curl_init('https://kverton.cz/api/v1/codes/1234');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer kv_XXXXXXXX_…', 'Content-Type: application/json'],
]);
$data = json_decode((string) curl_exec($ch), true);
const res = await fetch('https://kverton.cz/api/v1/codes/1234', {
method: 'GET',
headers: { Authorization: 'Bearer kv_XXXXXXXX_…', 'Content-Type': 'application/json' },
});
const data = await res.json();
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://kverton.cz/api/v1/codes/1234"))
.header("Authorization", "Bearer kv_XXXXXXXX_…")
.header("Content-Type", "application/json")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
String json = res.body();
/codes/{id}
Scope: write
Upravit kód
Změna cíle se zapíše do historie (rollback níže). Pošlete jen pole, která měníte. active=false kód pozastaví.
| Parameter | in | Type | |
|---|---|---|---|
| id * | path | integer | ID kódu |
Request body
{
"target_url": "https://eshop.cz/menu-zima",
"label": "Zimní menu",
"active": true,
"expires_at": null,
"password": "-",
"utm": {
"campaign": "zima"
},
"rules": [
{
"kind": "country",
"match": "SK",
"target_url": "https://eshop.sk/menu"
}
]
}Response
{
"id": 1234,
"slug": "a7k2m",
"short_url": "https://kvrt.net/a7k2m",
"label": "Podzimní menu",
"target_url": "https://eshop.cz/menu-podzim",
"active": true,
"expires_at": null,
"group_id": null,
"password_protected": false,
"utm": {
"source": "kverton",
"medium": "qr",
"campaign": null
},
"safety_state": "clear",
"created_at": "2026-09-01T10:00:00Z",
"last_scan_at": "2026-09-03T08:12:00Z"
}Samples: curl · PHP · JavaScript · Java
curl -X PATCH 'https://kverton.cz/api/v1/codes/1234' \
-H 'Authorization: Bearer kv_XXXXXXXX_…' \
-H 'Content-Type: application/json' \
-d '{"target_url":"https://eshop.cz/menu-zima","label":"Zimní menu","active":true,"expires_at":null,"password":"-","utm":{"campaign":"zima"},"rules":[{"kind":"country","match":"SK","target_url":"https://eshop.sk/menu"}]}'
<?php
$ch = curl_init('https://kverton.cz/api/v1/codes/1234');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer kv_XXXXXXXX_…', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(array (
'target_url' => 'https://eshop.cz/menu-zima',
'label' => 'Zimní menu',
'active' => true,
'expires_at' => NULL,
'password' => '-',
'utm' =>
array (
'campaign' => 'zima',
),
'rules' =>
array (
0 =>
array (
'kind' => 'country',
'match' => 'SK',
'target_url' => 'https://eshop.sk/menu',
),
),
)),
]);
$data = json_decode((string) curl_exec($ch), true);
const res = await fetch('https://kverton.cz/api/v1/codes/1234', {
method: 'PATCH',
headers: { Authorization: 'Bearer kv_XXXXXXXX_…', 'Content-Type': 'application/json' },
body: JSON.stringify({"target_url":"https://eshop.cz/menu-zima","label":"Zimní menu","active":true,"expires_at":null,"password":"-","utm":{"campaign":"zima"},"rules":[{"kind":"country","match":"SK","target_url":"https://eshop.sk/menu"}]}),
});
const data = await res.json();
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://kverton.cz/api/v1/codes/1234"))
.header("Authorization", "Bearer kv_XXXXXXXX_…")
.header("Content-Type", "application/json")
.method("PATCH", HttpRequest.BodyPublishers.ofString("{\"target_url\":\"https:\/\/eshop.cz\/menu-zima\",\"label\":\"Zimn\u00ed menu\",\"active\":true,\"expires_at\":null,\"password\":\"-\",\"utm\":{\"campaign\":\"zima\"},\"rules\":[{\"kind\":\"country\",\"match\":\"SK\",\"target_url\":\"https:\/\/eshop.sk\/menu\"}]}"))
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
String json = res.body();
/codes/{id}
Scope: write
Smazat kód
Nevratné — vytištěný kód přestane fungovat. Zvažte spíš active=false.
| Parameter | in | Type | |
|---|---|---|---|
| id * | path | integer | ID kódu |
Response
{
"deleted": true
}Samples: curl · PHP · JavaScript · Java
curl -X DELETE 'https://kverton.cz/api/v1/codes/1234' \ -H 'Authorization: Bearer kv_XXXXXXXX_…'
<?php
$ch = curl_init('https://kverton.cz/api/v1/codes/1234');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer kv_XXXXXXXX_…', 'Content-Type: application/json'],
]);
$data = json_decode((string) curl_exec($ch), true);
const res = await fetch('https://kverton.cz/api/v1/codes/1234', {
method: 'DELETE',
headers: { Authorization: 'Bearer kv_XXXXXXXX_…', 'Content-Type': 'application/json' },
});
const data = await res.json();
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://kverton.cz/api/v1/codes/1234"))
.header("Authorization", "Bearer kv_XXXXXXXX_…")
.header("Content-Type", "application/json")
.method("DELETE", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
String json = res.body();
/codes/{id}/stats
Scope: read
Statistika skenů
Po dnech (podle historie tarifu), země, regiony, města, jazyky. Bez IP adres — ty neukládáme.
| Parameter | in | Type | |
|---|---|---|---|
| id * | path | integer | ID kódu |
Response
{
"total": 166,
"last_24h": 12,
"days": [
{
"day": "2026-09-02",
"visits": 11,
"impressions": 13
}
],
"countries": [
{
"key": "CZ",
"count": 106
}
],
"cities": [
{
"key": "Praha",
"count": 61
}
],
"langs": [
{
"key": "cs",
"count": 120
}
]
}Samples: curl · PHP · JavaScript · Java
curl -X GET 'https://kverton.cz/api/v1/codes/1234/stats' \ -H 'Authorization: Bearer kv_XXXXXXXX_…'
<?php
$ch = curl_init('https://kverton.cz/api/v1/codes/1234/stats');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer kv_XXXXXXXX_…', 'Content-Type: application/json'],
]);
$data = json_decode((string) curl_exec($ch), true);
const res = await fetch('https://kverton.cz/api/v1/codes/1234/stats', {
method: 'GET',
headers: { Authorization: 'Bearer kv_XXXXXXXX_…', 'Content-Type': 'application/json' },
});
const data = await res.json();
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://kverton.cz/api/v1/codes/1234/stats"))
.header("Authorization", "Bearer kv_XXXXXXXX_…")
.header("Content-Type", "application/json")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
String json = res.body();
/codes/{id}/history
Scope: read
Historie cílů
Verze cíle, nejnovější první.
| Parameter | in | Type | |
|---|---|---|---|
| id * | path | integer | ID kódu |
Response
{
"data": [
{
"id": 501,
"target_url": "https://eshop.cz/menu-podzim",
"changed_at": "2026-09-01T10:00:00Z"
}
]
}Samples: curl · PHP · JavaScript · Java
curl -X GET 'https://kverton.cz/api/v1/codes/1234/history' \ -H 'Authorization: Bearer kv_XXXXXXXX_…'
<?php
$ch = curl_init('https://kverton.cz/api/v1/codes/1234/history');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer kv_XXXXXXXX_…', 'Content-Type: application/json'],
]);
$data = json_decode((string) curl_exec($ch), true);
const res = await fetch('https://kverton.cz/api/v1/codes/1234/history', {
method: 'GET',
headers: { Authorization: 'Bearer kv_XXXXXXXX_…', 'Content-Type': 'application/json' },
});
const data = await res.json();
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://kverton.cz/api/v1/codes/1234/history"))
.header("Authorization", "Bearer kv_XXXXXXXX_…")
.header("Content-Type", "application/json")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
String json = res.body();
/codes/{id}/rollback
Scope: write
Vrátit starší cíl
Návrat na verzi z historie; sám se zapíše jako nová verze.
| Parameter | in | Type | |
|---|---|---|---|
| id * | path | integer | ID kódu |
Request body
{
"history_id": 501
}Response
{
"id": 1234,
"slug": "a7k2m",
"short_url": "https://kvrt.net/a7k2m",
"label": "Podzimní menu",
"target_url": "https://eshop.cz/menu-podzim",
"active": true,
"expires_at": null,
"group_id": null,
"password_protected": false,
"utm": {
"source": "kverton",
"medium": "qr",
"campaign": null
},
"safety_state": "clear",
"created_at": "2026-09-01T10:00:00Z",
"last_scan_at": "2026-09-03T08:12:00Z"
}Samples: curl · PHP · JavaScript · Java
curl -X POST 'https://kverton.cz/api/v1/codes/1234/rollback' \
-H 'Authorization: Bearer kv_XXXXXXXX_…' \
-H 'Content-Type: application/json' \
-d '{"history_id":501}'
<?php
$ch = curl_init('https://kverton.cz/api/v1/codes/1234/rollback');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer kv_XXXXXXXX_…', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(array (
'history_id' => 501,
)),
]);
$data = json_decode((string) curl_exec($ch), true);
const res = await fetch('https://kverton.cz/api/v1/codes/1234/rollback', {
method: 'POST',
headers: { Authorization: 'Bearer kv_XXXXXXXX_…', 'Content-Type': 'application/json' },
body: JSON.stringify({"history_id":501}),
});
const data = await res.json();
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://kverton.cz/api/v1/codes/1234/rollback"))
.header("Authorization", "Bearer kv_XXXXXXXX_…")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"history_id\":501}"))
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
String json = res.body();
/groups
Scope: read
Skupiny kódů
Skupiny týmu s počty kódů.
Response
{
"data": [
{
"id": 3,
"name": "Akce",
"codes": 12
}
]
}Samples: curl · PHP · JavaScript · Java
curl -X GET 'https://kverton.cz/api/v1/groups' \ -H 'Authorization: Bearer kv_XXXXXXXX_…'
<?php
$ch = curl_init('https://kverton.cz/api/v1/groups');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer kv_XXXXXXXX_…', 'Content-Type: application/json'],
]);
$data = json_decode((string) curl_exec($ch), true);
const res = await fetch('https://kverton.cz/api/v1/groups', {
method: 'GET',
headers: { Authorization: 'Bearer kv_XXXXXXXX_…', 'Content-Type': 'application/json' },
});
const data = await res.json();
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://kverton.cz/api/v1/groups"))
.header("Authorization", "Bearer kv_XXXXXXXX_…")
.header("Content-Type", "application/json")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
String json = res.body();
/render
Scope: read
Vykreslit QR jako SVG
Obsah → SVG (vektor, čistý vzhled, klidová zóna). Pro dynamický kód pošlete jeho short_url. Formáty: qr, datamatrix, azteccode, rmqr.
Request body
{
"content": "https://kvrt.net/a7k2m",
"format": "qr",
"ecl": "M",
"module_color": "#302B23",
"background": "#FFFFFF"
}Response
{
"svg": "<svg …>",
"size": 29
}Samples: curl · PHP · JavaScript · Java
curl -X POST 'https://kverton.cz/api/v1/render' \
-H 'Authorization: Bearer kv_XXXXXXXX_…' \
-H 'Content-Type: application/json' \
-d '{"content":"https://kvrt.net/a7k2m","format":"qr","ecl":"M","module_color":"#302B23","background":"#FFFFFF"}'
<?php
$ch = curl_init('https://kverton.cz/api/v1/render');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer kv_XXXXXXXX_…', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(array (
'content' => 'https://kvrt.net/a7k2m',
'format' => 'qr',
'ecl' => 'M',
'module_color' => '#302B23',
'background' => '#FFFFFF',
)),
]);
$data = json_decode((string) curl_exec($ch), true);
const res = await fetch('https://kverton.cz/api/v1/render', {
method: 'POST',
headers: { Authorization: 'Bearer kv_XXXXXXXX_…', 'Content-Type': 'application/json' },
body: JSON.stringify({"content":"https://kvrt.net/a7k2m","format":"qr","ecl":"M","module_color":"#302B23","background":"#FFFFFF"}),
});
const data = await res.json();
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://kverton.cz/api/v1/render"))
.header("Authorization", "Bearer kv_XXXXXXXX_…")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"content\":\"https:\/\/kvrt.net\/a7k2m\",\"format\":\"qr\",\"ecl\":\"M\",\"module_color\":\"#302B23\",\"background\":\"#FFFFFF\"}"))
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
String json = res.body();
/webhooks
Scope: read
Webhooky týmu
Adresy, události, stav posledního doručení.
Response
{
"data": [
{
"id": 7,
"url": "https://example.cz/hooks/kverton",
"events": [
"scan",
"code.updated"
],
"active": true,
"last_status": 200
}
]
}Samples: curl · PHP · JavaScript · Java
curl -X GET 'https://kverton.cz/api/v1/webhooks' \ -H 'Authorization: Bearer kv_XXXXXXXX_…'
<?php
$ch = curl_init('https://kverton.cz/api/v1/webhooks');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer kv_XXXXXXXX_…', 'Content-Type: application/json'],
]);
$data = json_decode((string) curl_exec($ch), true);
const res = await fetch('https://kverton.cz/api/v1/webhooks', {
method: 'GET',
headers: { Authorization: 'Bearer kv_XXXXXXXX_…', 'Content-Type': 'application/json' },
});
const data = await res.json();
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://kverton.cz/api/v1/webhooks"))
.header("Authorization", "Bearer kv_XXXXXXXX_…")
.header("Content-Type", "application/json")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
String json = res.body();
/webhooks
Scope: write
Přidat webhook
Jen https. Tajemství (secret) se vrátí jednou — ověřujte jím podpis X-Kverton-Signature (sha256=HMAC-SHA256 těla).
Request body
{
"url": "https://example.cz/hooks/kverton",
"events": [
"scan",
"code.updated"
]
}Response
{
"id": 7,
"secret": "3f9c…"
}Samples: curl · PHP · JavaScript · Java
curl -X POST 'https://kverton.cz/api/v1/webhooks' \
-H 'Authorization: Bearer kv_XXXXXXXX_…' \
-H 'Content-Type: application/json' \
-d '{"url":"https://example.cz/hooks/kverton","events":["scan","code.updated"]}'
<?php
$ch = curl_init('https://kverton.cz/api/v1/webhooks');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer kv_XXXXXXXX_…', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(array (
'url' => 'https://example.cz/hooks/kverton',
'events' =>
array (
0 => 'scan',
1 => 'code.updated',
),
)),
]);
$data = json_decode((string) curl_exec($ch), true);
const res = await fetch('https://kverton.cz/api/v1/webhooks', {
method: 'POST',
headers: { Authorization: 'Bearer kv_XXXXXXXX_…', 'Content-Type': 'application/json' },
body: JSON.stringify({"url":"https://example.cz/hooks/kverton","events":["scan","code.updated"]}),
});
const data = await res.json();
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://kverton.cz/api/v1/webhooks"))
.header("Authorization", "Bearer kv_XXXXXXXX_…")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"url\":\"https:\/\/example.cz\/hooks\/kverton\",\"events\":[\"scan\",\"code.updated\"]}"))
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
String json = res.body();
/webhooks/{id}
Scope: write
Odebrat webhook
Nedoručené události se zahodí.
| Parameter | in | Type | |
|---|---|---|---|
| id * | path | integer | ID webhooku |
Response
{
"deleted": true
}Samples: curl · PHP · JavaScript · Java
curl -X DELETE 'https://kverton.cz/api/v1/webhooks/1234' \ -H 'Authorization: Bearer kv_XXXXXXXX_…'
<?php
$ch = curl_init('https://kverton.cz/api/v1/webhooks/1234');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer kv_XXXXXXXX_…', 'Content-Type: application/json'],
]);
$data = json_decode((string) curl_exec($ch), true);
const res = await fetch('https://kverton.cz/api/v1/webhooks/1234', {
method: 'DELETE',
headers: { Authorization: 'Bearer kv_XXXXXXXX_…', 'Content-Type': 'application/json' },
});
const data = await res.json();
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://kverton.cz/api/v1/webhooks/1234"))
.header("Authorization", "Bearer kv_XXXXXXXX_…")
.header("Content-Type", "application/json")
.method("DELETE", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
String json = res.body();
/webhooks/{id}/test
Scope: write
Zkušební událost
Zařadí událost webhook.test; doručí se do minuty.
| Parameter | in | Type | |
|---|---|---|---|
| id * | path | integer | ID webhooku |
Response
{
"queued": true
}Samples: curl · PHP · JavaScript · Java
curl -X POST 'https://kverton.cz/api/v1/webhooks/1234/test' \ -H 'Authorization: Bearer kv_XXXXXXXX_…'
<?php
$ch = curl_init('https://kverton.cz/api/v1/webhooks/1234/test');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer kv_XXXXXXXX_…', 'Content-Type: application/json'],
]);
$data = json_decode((string) curl_exec($ch), true);
const res = await fetch('https://kverton.cz/api/v1/webhooks/1234/test', {
method: 'POST',
headers: { Authorization: 'Bearer kv_XXXXXXXX_…', 'Content-Type': 'application/json' },
});
const data = await res.json();
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://kverton.cz/api/v1/webhooks/1234/test"))
.header("Authorization", "Bearer kv_XXXXXXXX_…")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
String json = res.body();
Webhooks
On an event we POST a JSON body to your https URL. Verify the body signature with the webhook secret (returned once on creation).
POST https://example.cz/hooks/kverton Content-Type: application/json X-Kverton-Event: scan X-Kverton-Delivery: 8812 X-Kverton-Signature: sha256=<HMAC-SHA256(secret, body)>
scan — Někdo načetl dynamický kód (bez IP adresy; země a jazyk podle GeoIP).
{
"event": "scan",
"created_at": "2026-09-03T08:12:00Z",
"data": {
"code_id": 1234,
"slug": "a7k2m",
"country": "CZ",
"lang": "cs",
"kind": "visit"
}
}
code.created — Vznikl dynamický kód.
{
"event": "code.created",
"created_at": "2026-09-03T08:12:00Z",
"data": {
"code_id": 1234,
"slug": "a7k2m",
"target_url": "https://eshop.cz/menu"
}
}
code.updated — Změnil se cíl kódu (i rollbackem).
{
"event": "code.updated",
"created_at": "2026-09-03T08:12:00Z",
"data": {
"code_id": 1234,
"target_url": "https://eshop.cz/menu-zima"
}
}
code.deleted — Kód byl smazán.
{
"event": "code.deleted",
"created_at": "2026-09-03T08:12:00Z",
"data": {
"code_id": 1234
}
}
A delivery counts on a 2xx response. Otherwise we retry after 1 min, 5 min, 30 min, 2 h and 12 h; after 20 consecutive failures the webhook is disabled and shown as such in team settings.
// PHP: verify the signature
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
if (!hash_equals($expected, $_SERVER['HTTP_X_KVERTON_SIGNATURE'] ?? '')) { http_response_code(401); exit; }
Libraries
Official thin libraries under the MIT licence — open source on GitHub under the kverton organisation. One method per endpoint; errors as exceptions; webhook signature verification included.
PHP Composer
composer require kverton/kverton-php
$kverton = new \Kverton\Sdk\Client('kv_…');
$code = $kverton->createCode([
'label' => 'Menu',
'target_url' => 'https://example.cz/menu',
]);
echo $code['short_url'];
github.com/kverton/kverton-php · Packagist
PHP 8.1+, no dependencies (curl or streams).
JavaScript / TypeScript npm
npm install @kverton/sdk
import { KvertonClient } from '@kverton/sdk';
const kverton = new KvertonClient('kv_…');
const code = await kverton.createCode({
label: 'Menu',
target_url: 'https://example.cz/menu',
});
console.log(code.short_url);
github.com/kverton/kverton-js · npm
Node 18+, Deno, Bun, edge — global fetch; fully typed.
MCP AI asistenti
npx -y @kverton/mcp
{
"mcpServers": {
"kverton": {
"command": "npx",
"args": ["-y", "@kverton/mcp"],
"env": { "KVERTON_API_KEY": "kv_…" }
}
}
}
github.com/kverton/kverton-mcp · MCP →
Claude, ChatGPT, Cursor and others — 13 tools over the API.
Another language? The OpenAPI description generates a client (openapi-generator): /api/v1/openapi.json