مرجع الواجهة البرمجية

مواصفة حيّة ومصانة يدوياً، معروضة عبر Scalar. انقر أي نقطة نهاية واستخدم Test Request لإرسال طلب حقيقي.

البدء السريع، في 60 ثانية

  1. 1. أنشئ مفتاحاً في الإعدادات ← مفاتيح API بنطاق links:write.
  2. 2. أرسل طلبك الأول:
    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" }'
  3. 3. زُر short_url المُعاد لاختبار التوجيه، ثم استعلم /api/v1/links/{code}/stats?period=7d للحصول على التحليلات.

المفاهيم الأساسية

Qrindo Public API v1.0 · 40 نقطة نهاية عامة · العنوان الأساسي: https://api.qrindo.com/api/v1

Overview

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.

Authentication

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

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..."
}

Idempotency

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.

Rate limits

Per-key per-minute, with RFC 9331 headers (RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset).

كل نقاط النهاية

المرجع التفاعلي أدناه يقرأ المواصفة نفسها ويتيح إرسال طلبات حقيقية.

Identity

GET /me

Inspect current API key

المصادقة: BearerAuth

الاستجابات

الحالةالوصف
200OK

POST /links

Create a link

المصادقة: 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 —

الاستجابات

الحالةالوصف
201Created
400Validation failed
409Code conflict or idempotency mismatch

POST /links/{code}/rotate

Rotate the destination, keep the code

المصادقة: BearerAuth

المعاملات

الاسمالموضعالنوعمطلوبالوصف
code path string نعم

حقول الطلب (JSON)

الاسمالنوعمطلوبالوصف
target_url string (uri) نعم

الاستجابات

الحالةالوصف
200OK

POST /links/batch

Create up to 100 links in one call

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[] نعم

الاستجابات

الحالةالوصف
201All created
207Partial success
401Missing, malformed, expired, or revoked token.

POST /links/import

Bulk import links from CSV

Accepts text/csv or multipart/form-data (a `file` field). CSV columns: target_url,code,title,tags (tags pipe-separated).

المصادقة: BearerAuth

الاستجابات

الحالةالوصف
201All imported
207Partial import
413Upload exceeds the size limit.

QR

GET /qr/{codeAndExt}

Render a stored link's QR

المصادقة: BearerAuth

المعاملات

الاسمالموضعالنوعمطلوبالوصف
codeAndExt path string نعم
size query integer —
fg query string —
bg query string —
ec query "L" | "M" | "Q" | "H" —

الاستجابات

الحالةالوصف
200PNG or SVG bytes

POST /qr/render

Render arbitrary content (no link stored)

المصادقة: BearerAuth

حقول الطلب (JSON)

الاسمالنوعمطلوبالوصف
content string نعم
format "png" | "svg" —
size integer —
fg string —
bg string —
ec "L" | "M" | "Q" | "H" —

الاستجابات

الحالةالوصف
200Rendered image

POST /qr/batch

Render many stored links into one ZIP

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 —

الاستجابات

الحالةالوصف
200ZIP archive of QR images
404None of the provided codes resolved to a link

Analytics

Events

GET /events

List raw scan events

المصادقة: BearerAuth

المعاملات

الاسمالموضعالنوعمطلوبالوصف
cursor query string —
limit query integer —
from query string (date-time) —
to query string (date-time) —
code query string —

الاستجابات

الحالةالوصف
200OK

Public

POST /public/preview

Demo-only: ten-minute disposable short link

المصادقة: عام

حقول الطلب (JSON)

الاسمالنوعمطلوبالوصف
target_url string (uri) نعم

الاستجابات

الحالةالوصف
200Disposable short link + QR
429Per-key minute window exceeded.

GET /public/stats/{code}

Public scan stats for a link (no auth)

المصادقة: عام

المعاملات

الاسمالموضعالنوعمطلوبالوصف
code path string نعم

الاستجابات

الحالةالوصف
200OK
404Resource not found.
429Per-key minute window exceeded.

GET /public/preview/{codeAndExt}

QR image for a demo preview link

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 نعم

الاستجابات

الحالةالوصف
200QR image
404Resource not found.

GET /public/platform-stats

Aggregate platform counters

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.

المصادقة: عام

الاستجابات

الحالةالوصف
200OK

Webhooks

GET /webhooks

List webhook subscriptions

المصادقة: BearerAuth

الاستجابات

الحالةالوصف
200OK
401Missing, malformed, expired, or revoked token.

POST /webhooks

Create a webhook subscription

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 —

الاستجابات

الحالةالوصف
201Created (secret returned once)
400Validation failed.
402Plan webhook limit reached

DELETE /webhooks/{id}

Delete a webhook subscription

المصادقة: BearerAuth

المعاملات

الاسمالموضعالنوعمطلوبالوصف
id path string نعم

الاستجابات

الحالةالوصف
204Deleted
404Resource not found.

POST /webhooks/{id}/test

Send a test delivery (webhook.test event)

المصادقة: BearerAuth

المعاملات

الاسمالموضعالنوعمطلوبالوصف
id path string نعم

الاستجابات

الحالةالوصف
200Queued

GET /webhooks/{id}/deliveries

List recent delivery attempts for a webhook

المصادقة: BearerAuth

المعاملات

الاسمالموضعالنوعمطلوبالوصف
id path string نعم

الاستجابات

الحالةالوصف
200OK
404Resource not found.

POST /deeplinks

Create a deeplink

المصادقة: BearerAuth

حقول الطلب (JSON)

الاسمالنوعمطلوبالوصف
code string —
title string —
targets object —
active boolean —

الاستجابات

الحالةالوصف
201Created
400Validation failed.

Sites

GET /sites

List sites

Every site in the workspace the API key belongs to. Not paginated.

المصادقة: BearerAuth

الاستجابات

الحالةالوصف
200OK
401Missing, malformed, expired, or revoked token.

POST /sites

Create a site

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 —

الاستجابات

الحالةالوصف
201Created
400Validation failed.
401Missing, malformed, expired, or revoked token.

GET /sites/{id}

Get one site

المصادقة: BearerAuth

المعاملات

الاسمالموضعالنوعمطلوبالوصف
id path string نعم Site id (ULID).

الاستجابات

الحالةالوصف
200OK
404Resource not found.

GET /sites/{id}/units

List the units of a site

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).

الاستجابات

الحالةالوصف
200OK
404Resource not found.

POST /sites/{id}/units/batch

Create units in bulk

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.

الاستجابات

الحالةالوصف
201Created (inspect `results` for per-unit outcomes)
400Validation failed.
404Resource not found.

GET /sites/{id}/leaderboard

Scan leaderboard for a site

Units ranked by scan count, plus the count of units never scanned.

المصادقة: BearerAuth

المعاملات

الاسمالموضعالنوعمطلوبالوصف
id path string نعم Site id (ULID).

الاستجابات

الحالةالوصف
200OK
404Resource not found.

Conversions

POST /conversions

Report a conversion against a scan

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 —

الاستجابات

الحالةالوصف
200Already recorded. The same `external_id` arrived before; this is the answer to a retry and carries the id of the conversion that already exists.
201Recorded
400No join key was sent, or the body failed validation.
404The code is not one this key's workspace owns.

OAuth

POST /oauth/token

Issue an access 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 —

الاستجابات

الحالةالوصف
200Token issued
400Unsupported grant type
401Invalid client
415Unsupported content type

جرّب طلبًا حقيقيًا

المرجع الكامل أعلاه جزء من هذه الصفحة. أمّا أداة الاختبار التفاعلية فهي حزمة من طرف ثالث (Scalar)، ولذلك لا تُحمَّل إلا عندما تطلبها. انقر أي نقطة نهاية بداخلها واستخدم Test Request لإرسال طلب حقيقي.

تفضّل المستند الخام؟ /openapi.yaml