GET /me
Inspect current API key
المصادقة: BearerAuth
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
مواصفة حيّة ومصانة يدوياً، معروضة عبر Scalar. انقر أي نقطة نهاية واستخدم Test Request لإرسال طلب حقيقي.
links:write.
curl -X POST https://api.qrindo.com/api/v1/links \
-H "Authorization: Bearer $QRINDO_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{ "target_url": "https://example.com/launch", "title": "Launch" }' short_url المُعاد لاختبار التوجيه، ثم استعلم
/api/v1/links/{code}/stats?period=7d للحصول على التحليلات.
Qrindo Public API v1.0 · 40 نقطة نهاية عامة · العنوان الأساسي: https://api.qrindo.com/api/v1
Bearer-token (API key or OAuth client_credentials) REST API for the Qrindo platform. Designed for partner products that need to mint dynamic links, render QR codes, read analytics, and subscribe to scan events.
Every request requires Authorization: Bearer <token>.
| Token kind | Format | Best for |
|---|---|---|
| API key | qrf_live_… / qrf_test_… |
Long-lived backend integrations |
| OAuth access token | JWT (RS256) | Compliance / rotation-heavy partners |
Errors follow RFC 7807 problem-json.
{
"type": "https://qrindo.com/errors/rate_limited",
"title": "Too many requests",
"status": 429,
"code": "rate_limited",
"detail": "Rate limit exceeded: 10000 req/min per API key. Retry in 12s.",
"instance": "01HRV..."
}
Pass Idempotency-Key: <uuid> on any POST. Retrying with the same key + body
replays the cached response. Retrying with a different body returns
409 idempotency_replay_mismatch.
Per-key per-minute, with RFC 9331
headers (RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset).
المرجع التفاعلي أدناه يقرأ المواصفة نفسها ويتيح إرسال طلبات حقيقية.
GET /me
المصادقة: BearerAuth
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
GET /links
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
cursor | query | string | — | |
limit | query | integer | — |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
401 | Missing, malformed, expired, or revoked token. |
429 | Per-key minute window exceeded. |
POST /links
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
Idempotency-Key | header | string | — |
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
target_url | string (uri) | نعم | |
code | string | — | Optional vanity slug. 4-8 chars, [A-Za-z0-9_-]. |
title | string | — | |
active | boolean | — |
الاستجابات
| الحالة | الوصف |
|---|---|
201 | Created |
400 | Validation failed |
409 | Code conflict or idempotency mismatch |
GET /links/{code}
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
code | path | string | نعم |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
404 | Resource not found. |
PATCH /links/{code}
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
code | path | string | نعم |
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
target_url | string (uri) | — | |
title | string | — | |
active | boolean | — |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
DELETE /links/{code}
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
code | path | string | نعم |
الاستجابات
| الحالة | الوصف |
|---|---|
204 | Deleted |
404 | Resource not found. |
POST /links/{code}/rotate
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
code | path | string | نعم |
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
target_url | string (uri) | نعم |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
POST /links/batch
Returns 201 if all succeed, 207 (multi-status) on partial failure. Each item reports its own success/error.
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
Idempotency-Key | header | string | — |
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
items | CreateLink[] | نعم |
الاستجابات
| الحالة | الوصف |
|---|---|
201 | All created |
207 | Partial success |
401 | Missing, malformed, expired, or revoked token. |
PATCH /links/batch
المصادقة: BearerAuth
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
codes | string[] | نعم | |
active | boolean | — | |
tags | string[] | — | |
folder_id | string | — |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
207 | Partial success |
DELETE /links/batch
المصادقة: BearerAuth
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
codes | string[] | نعم |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
207 | Partial success |
POST /links/import
Accepts text/csv or multipart/form-data (a `file` field). CSV columns: target_url,code,title,tags (tags pipe-separated).
المصادقة: BearerAuth
الاستجابات
| الحالة | الوصف |
|---|---|
201 | All imported |
207 | Partial import |
413 | Upload exceeds the size limit. |
GET /qr/{codeAndExt}
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
codeAndExt | path | string | نعم | |
size | query | integer | — | |
fg | query | string | — | |
bg | query | string | — | |
ec | query | "L" | "M" | "Q" | "H" | — |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | PNG or SVG bytes |
POST /qr/render
المصادقة: BearerAuth
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
content | string | نعم | |
format | "png" | "svg" | — | |
size | integer | — | |
fg | string | — | |
bg | string | — | |
ec | "L" | "M" | "Q" | "H" | — |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | Rendered image |
POST /qr/batch
Renders up to 50 of your links as PNG or SVG and streams them back as a single ZIP archive. Codes that don't belong to the workspace are skipped.
المصادقة: BearerAuth
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
codes | string[] | نعم | |
format | "png" | "svg" | — | |
size | integer | — | |
fg | string | — | |
bg | string | — |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | ZIP archive of QR images |
404 | None of the provided codes resolved to a link |
GET /links/{code}/stats
Scans over time. `granularity` controls the bucket size; a size too fine for the window is rejected with 400 rather than silently downgraded, and a response never exceeds 1500 points.
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
code | path | string | نعم | |
period | query | "7d" | "30d" | "90d" | "1y" | — | |
from | query | string | — | Window start: a calendar day (YYYY-MM-DD, read in `tz`) or a full ISO instant. Instants are what make sub-day resolution reachable. |
to | query | string | — | Window end, same formats as `from`. Exclusive. |
tz | query | string | — | IANA zone every bucket and timestamp is expressed in. Defaults to UTC, which is rarely what you want if your audience is not in it. |
granularity | query | "auto" | "minute" | "5min" | "hour" | "day" | "week" | — |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
GET /links/{code}/breakdown
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
code | path | string | نعم | |
period | query | "7d" | "30d" | "90d" | "1y" | — | |
from | query | string | — | Window start: a calendar day (YYYY-MM-DD, read in `tz`) or a full ISO instant. Instants are what make sub-day resolution reachable. |
to | query | string | — | Window end, same formats as `from`. Exclusive. |
tz | query | string | — | IANA zone every bucket and timestamp is expressed in. Defaults to UTC, which is rarely what you want if your audience is not in it. |
dim | query | "country" | "device" | "os" | "browser" | "referrer" | — |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
GET /links/{code}/events
One row per recorded scan, newest first, each with its exact timestamp. Keyset-paginated: pass the previous response's `next_cursor` as `cursor`. There is no offset and no total count, both are expensive on the underlying time-series table. Individual scans are retained for 365 days.
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
code | path | string | نعم | |
period | query | "7d" | "30d" | "90d" | "1y" | — | |
from | query | string | — | Window start: a calendar day (YYYY-MM-DD, read in `tz`) or a full ISO instant. Instants are what make sub-day resolution reachable. |
to | query | string | — | Window end, same formats as `from`. Exclusive. |
tz | query | string | — | IANA zone every bucket and timestamp is expressed in. Defaults to UTC, which is rarely what you want if your audience is not in it. |
cursor | query | string | — | |
limit | query | integer | — | |
include_bots | query | boolean | — | Bots are excluded unless you ask for them. |
country | query | string | — | |
city | query | string | — | |
region | query | string | — | |
device | query | string | — | |
os | query | string | — | |
browser | query | string | — | |
referrer_host | query | string | — | |
visitor | query | string | — | Salted visitor hash, as returned in `visitor`. |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
GET /events
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
cursor | query | string | — | |
limit | query | integer | — | |
from | query | string (date-time) | — | |
to | query | string (date-time) | — | |
code | query | string | — |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
POST /public/preview
المصادقة: عام
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
target_url | string (uri) | نعم |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | Disposable short link + QR |
429 | Per-key minute window exceeded. |
GET /public/stats/{code}
المصادقة: عام
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
code | path | string | نعم |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
404 | Resource not found. |
429 | Per-key minute window exceeded. |
GET /public/preview/{codeAndExt}
Renders the QR for a code created by `POST /public/preview`. Unauthenticated and rate-limited. The preview expires 10 minutes after creation, after which this returns 404.
المصادقة: عام
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
codeAndExt | path | string | نعم |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | QR image |
404 | Resource not found. |
GET /public/platform-stats
Lifetime totals powering the marketing site's live numbers. Unauthenticated, rate-limited, and served from a 5-minute cache — `cached: true` marks a response served from it. Scans are lifetime per-link counters, so the number never decreases as old scan events age out of retention.
المصادقة: عام
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
GET /webhooks
المصادقة: BearerAuth
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
401 | Missing, malformed, expired, or revoked token. |
POST /webhooks
The `secret` is returned once; use it to verify the Qrindo-Signature header (t=...,v1=HMAC-SHA256("{t}.{rawBody}")).
المصادقة: BearerAuth
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
url | string (uri) | نعم | |
events | "scan.created" | "link.created" | "link.updated" | "link.deleted"[] | نعم | |
active | boolean | — |
الاستجابات
| الحالة | الوصف |
|---|---|
201 | Created (secret returned once) |
400 | Validation failed. |
402 | Plan webhook limit reached |
DELETE /webhooks/{id}
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
id | path | string | نعم |
الاستجابات
| الحالة | الوصف |
|---|---|
204 | Deleted |
404 | Resource not found. |
POST /webhooks/{id}/test
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
id | path | string | نعم |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | Queued |
GET /webhooks/{id}/deliveries
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
id | path | string | نعم |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
404 | Resource not found. |
GET /deeplinks
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
cursor | query | string | — | |
limit | query | integer | — |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
401 | Missing, malformed, expired, or revoked token. |
POST /deeplinks
المصادقة: BearerAuth
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
code | string | — | |
title | string | — | |
targets | object | — | |
active | boolean | — |
الاستجابات
| الحالة | الوصف |
|---|---|
201 | Created |
400 | Validation failed. |
GET /deeplinks/{code}
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
code | path | string | نعم |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
404 | Resource not found. |
PATCH /deeplinks/{code}
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
code | path | string | نعم |
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
code | string | — | |
title | string | — | |
targets | object | — | |
active | boolean | — |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
DELETE /deeplinks/{code}
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
code | path | string | نعم |
الاستجابات
| الحالة | الوصف |
|---|---|
204 | Deleted |
404 | Resource not found. |
GET /sites
Every site in the workspace the API key belongs to. Not paginated.
المصادقة: BearerAuth
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
401 | Missing, malformed, expired, or revoked token. |
POST /sites
Requires the `links:write` scope.
المصادقة: BearerAuth
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
name | string | نعم | |
pack_key | string | — | Unit template pack to seed labels and destinations from. |
external_id | string | — | |
address | string | — |
الاستجابات
| الحالة | الوصف |
|---|---|
201 | Created |
400 | Validation failed. |
401 | Missing, malformed, expired, or revoked token. |
GET /sites/{id}
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
id | path | string | نعم | Site id (ULID). |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
404 | Resource not found. |
GET /sites/{id}/units
Returns units in fixed unit-number order, including any gaps left by deleted units, so a printed sheet keeps its numbering.
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
id | path | string | نعم | Site id (ULID). |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
404 | Resource not found. |
POST /sites/{id}/units/batch
Creates up to 100 units and a link code for each. Per-unit success and failure are reported individually; the call itself returns 201 even when some units failed. Requires the `links:write` scope.
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
id | path | string | نعم | Site id (ULID). |
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
count | integer | — | |
start_at | integer | — | First unit number. Defaults to the site's next free number. |
label_pattern | string | — | Label template, e.g. "Table {n}". |
zone | string | — | |
destination | object | نعم | What every created unit points at. Same shape as a link's content. |
الاستجابات
| الحالة | الوصف |
|---|---|
201 | Created (inspect `results` for per-unit outcomes) |
400 | Validation failed. |
404 | Resource not found. |
GET /sites/{id}/leaderboard
Units ranked by scan count, plus the count of units never scanned.
المصادقة: BearerAuth
المعاملات
| الاسم | الموضع | النوع | مطلوب | الوصف |
|---|---|---|---|---|
id | path | string | نعم | Site id (ULID). |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | OK |
404 | Resource not found. |
POST /conversions
Closes the loop on a scan. The redirect hands your destination a join key (`qr_click_id`); you hand a conversion back against it, and the scan that started it finally has an outcome. **Idempotency is the contract.** Every platform that sends conversion callbacks retries them — on a timeout, on a 500, on a deploy — and revenue that doubles on a retry is more dangerous than revenue that is missing: a missing number gets investigated, an inflated one gets believed. Send `external_id` (your own id for the conversion) and a replay answers `200` with `duplicate: true`, never an error you would queue and retry forever. Without it, a retry is indistinguishable from a second sale. **Send at least one join key** — `code`, `click_ref`, `session_id` or `visitor`. With none of them the conversion belongs to the workspace and to nothing inside it, which is a number that can be summed and never explained, so it is refused rather than accepted as an orphan. `value_cents` is in MINOR units and the field name says so: a field called `value` taking 12.50 from one integrator and 1250 from the next is a bug nobody can reproduce, and floating-point money is how a revenue report ends up fractionally wrong with nobody able to say why.
المصادقة: BearerAuth
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
code | string | — | The short code. A code your key does not own is a 404, never someone else's attribution. |
click_ref | string | — | The `qr_click_id` the redirect appended to your destination URL. |
session_id | string | — | |
visitor | string | — | |
kind | string | — | Your name for this kind of conversion, e.g. `purchase`, `booking`. |
value_cents | integer | — | Minor units. 1250 is 12.50. |
currency | string | — | ISO 4217, three letters. |
external_id | string | — | Your id for this conversion. Send it — it is what makes a retry safe. |
occurred_at | string (date-time) | — | When it happened, if not now. ISO 8601. |
metadata | object | — |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | Already recorded. The same `external_id` arrived before; this is the answer to a retry and carries the id of the conversion that already exists. |
201 | Recorded |
400 | No join key was sent, or the body failed validation. |
404 | The code is not one this key's workspace owns. |
POST /oauth/token
Client-credentials grant. Accepts `application/x-www-form-urlencoded` (per RFC 6749) or `application/json`; any other content type is 415. `client_credentials` is the only supported grant type. Errors use the OAuth `{error, error_description}` shape, NOT the RFC 9457 problem document the rest of this API returns.
المصادقة: عام
حقول الطلب (JSON)
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
grant_type | "client_credentials" | نعم | |
client_id | string | نعم | |
client_secret | string | نعم | |
scope | string | — |
الاستجابات
| الحالة | الوصف |
|---|---|
200 | Token issued |
400 | Unsupported grant type |
401 | Invalid client |
415 | Unsupported content type |
المرجع الكامل أعلاه جزء من هذه الصفحة. أمّا أداة الاختبار التفاعلية فهي حزمة من طرف ثالث (Scalar)، ولذلك لا تُحمَّل إلا عندما تطلبها. انقر أي نقطة نهاية بداخلها واستخدم Test Request لإرسال طلب حقيقي.
تفضّل المستند الخام؟ /openapi.yaml