← Docs

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_xxxxxxxxxxxxxxxx

Base URL: https://qr-top.com/api/v1 — JSON responses wrapped in { "data": … }; errors return { "error": "message" } with the matching HTTP status.

Endpoints

Method and pathWhat it does
GET /linksLists links with scan counts
POST /linksCreates a link (destinationUrl required; title, slug*, routingRules*, expiresAt*, expiredUrl, utmParams optional)
POST /links/bulkCreates 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/:idLink detail
PATCH /links/:idUpdates destination, title, status, or smart routing*
DELETE /links/:idDeletes the link and its scans (irreversible)
GET /links/:id/statsAnalytics: totals, today, 7 days, devices, and daily series
GET /meOrganization, 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

CodeMeaning
200 / 201OK / resource created
400Invalid request (non-http/https URL, malformed rule…)
401API key missing, invalid, or expired
403Feature or limit not included in your plan
404Resource doesn't exist or isn't your organization's
409Slug already in use
429Rate limit exceeded

Rather not write code? Connect your AI assistant via MCP and just ask.

MCP connector guide →