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) |
| POST /links/bulk | Creates up to 200 links in one call ({ items: [...] }, same fields as POST /links). All-or-nothing: if any item fails validation, nothing is created and the response lists per-index errors. Counts as a single rate-limit request |
| 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.
Parameter passthrough (every plan): any query string on the short URL travels to the final destination — q-r.top/promo?utm_source=email delivers utm_source=email to your site. One link attributes multiple channels, and on collisions the incoming parameter wins over the link's fixed UTMs.
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" }
]
}'Bulk creation
Need 1,000 QRs for a catalog, an event, or a packaging batch? POST /links/bulk accepts up to 200 links per call with the same fields as single creation. It's all-or-nothing: if any item fails validation, nothing is created and the response lists each failing index — never a half-created batch. Each call counts once against the rate limit, so bulk is always the efficient path.
Terminal
curl -X POST https://qr-top.com/api/v1/links/bulk \
-H "Authorization: Bearer qr_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "destinationUrl": "https://shop.com/p/001", "title": "Product 001" },
{ "destinationUrl": "https://shop.com/p/002", "title": "Product 002" }
]
}'
# → 201 { "data": [ ...full links in request order... ], "count": 2 }
# → 400 { "error": "...", "errors": [ { "index": 1, "error": "..." } ] }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.