REST API
Manage your links and query analytics from your own systems. The API is included on every plan — what scales with the plan is volume and request limits.
Authentication
Create an API key under Settings → API in your account and send it with every request. The key determines your organization: you only see and modify your own links.
Authorization: Bearer qr_live_xxxxxxxxxxxxxxxxBase URL: https://qr-top.com/api/v1 — JSON responses wrapped in { "data": … }; errors return { "error": "message" } with the matching HTTP status.
Endpoints
| Method and path | What it does |
|---|---|
| GET /links | Lists links with scan counts |
| POST /links | Creates a link (destinationUrl required; title, slug*, routingRules*, expiresAt*, expiredUrl, utmParams optional) |
| GET /links/:id | Link detail |
| PATCH /links/:id | Updates destination, title, status, or smart routing* |
| DELETE /links/:id | Deletes the link and its scans (irreversible) |
| GET /links/:id/stats | Analytics: totals, today, 7 days, devices, and daily series |
| GET /me | Organization, plan, usage against limits, and features |
* Custom slugs and smart routing (rules by device/language/country/time, A/B, scan caps, expiry) require the Pro plan or higher. The backupUrl field (404 safeguard: we monitor your destination and switch to the backup if it goes down, with an email alert) requires Business. Out of plan they return a 403 with a clear message.
Example: create a link with a time-window rule
Terminal
curl -X POST https://qr-top.com/api/v1/links \
-H "Authorization: Bearer qr_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"destinationUrl": "https://example.com/menu",
"title": "Restaurant menu",
"routingRules": [
{ "hours": { "from": "08:00", "to": "12:00", "tz": "Europe/Madrid" },
"to": "https://example.com/breakfast" }
]
}'Rate limits
Per organization and minute, sliding window: 30 on Free, 100 on Pro and Business. Past it you'll get a 429 with X-RateLimit-* headers; retry with backoff. Scans of your QRs never consume this limit — they're unlimited on every plan.
Scan webhooks (Business)
Configure a URL under Settings → API and every recorded scan sends a real-time JSON POST — ideal for Zapier, Make, n8n, or your own backend. The body is signed with HMAC-SHA256 in the X-QRTop-Signature header so you can verify authenticity. No retries: if your receiver doesn't respond, the event is lost (the data stays in Analytics).
Payload
{
"event": "scan",
"link": { "id": "k3j2h1g4f5d6", "slug": "promo", "shortUrl": "https://q-r.top/promo" },
"scan": {
"scannedAt": "2026-07-25T12:34:56.000Z",
"country": "ES", "city": "Madrid", "region": "MD",
"deviceType": "mobile", "referer": null
}
}Verification
// Signature verification (Node.js)
const crypto = require("crypto");
const expected = "sha256=" + crypto
.createHmac("sha256", process.env.QRTOP_WEBHOOK_SECRET)
.update(rawBody)
.digest("hex");
const valid = expected === req.headers["x-qrtop-signature"];Status codes
| Code | Meaning |
|---|---|
| 200 / 201 | OK / resource created |
| 400 | Invalid request (non-http/https URL, malformed rule…) |
| 401 | API key missing, invalid, or expired |
| 403 | Feature or limit not included in your plan |
| 404 | Resource doesn't exist or isn't your organization's |
| 409 | Slug already in use |
| 429 | Rate limit exceeded |
Rather not write code? Connect your AI assistant via MCP and just ask.