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

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

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 →