Developer documentation

Business QR API

Create a branded QR code for each ticket, order or booking from your own backend.

Quickstart

Enable Business or Business Plus, then create a workspace API key with qr:write. Set LINKWAVE_URL to your Linkwave deployment origin and LINKWAVE_API_KEY to your secret key on your server.

curl -X POST "$LINKWAVE_URL/api/v1/qr-codes" \
  -H "Authorization: Bearer $LINKWAVE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: ticket:ticket_987:v1" \
  --data '{
  "name": "Ticket ticket_987",
  "mode": "static",
  "payload": "https://tickets.example.com/validate/unguessable-token",
  "design": {
    "template": "ticket",
    "label": "ADMIT ONE",
    "foreground": "#16181d",
    "background": "#ffffff",
    "logo": {
      "preset": "calendar"
    }
  }
}'

A successful creation returns HTTP 201. The response includes data.id, data.image.svg, and data.image.data_uri. SVG is a vector image; the API does not create the complete ticket PDF.

{
  "data": {
    "id": "8cb37fde-49cb-4f33-9d72-32fe81376d17",
    "name": "Ticket ticket_987",
    "mode": "static",
    "payload": "https://tickets.example.com/validate/unguessable-token",
    "encoded_value": "https://tickets.example.com/validate/unguessable-token",
    "status": "active",
    "created_at": "2026-10-17T12:00:00Z",
    "image_endpoint": "https://YOUR_LINKWAVE_HOST/api/v1/qr-codes/8cb37fde-49cb-4f33-9d72-32fe81376d17/image",
    "image": {
      "format": "svg",
      "svg": "<svg ...>...</svg>",
      "data_uri": "data:image/svg+xml;charset=utf-8,..."
    }
  }
}

Authentication

Authorization: Bearer lw_live_YOUR_SECRET_KEY

Workspace owners and admins can create and revoke keys in API access. A key is shown once; only its SHA-256 hash is stored. Keys expire after 30, 90 or 365 days. Create a replacement, update your integration, then revoke the old key to rotate without interruption.

qr:write creates QR codes. qr:read lists QR codes, retrieves images and reads the design catalog. All requests are restricted to the key's workspace. Revoked keys, expired keys, deleted workspaces and inactive subscriptions are rejected. API keys must stay on your server; browser CORS access is not enabled.

Ticketing workflow

  1. Your backend verifies the payment provider's webhook and confirms the order is paid.
  2. Create one opaque validation token or validation URL per ticket in your ticketing database.
  3. Call the API once per ticket using an idempotency key such as ticket:ticket_987:v1. Multiple tickets in an order need distinct keys.
  4. Store the returned QR ID with the ticket and embed the SVG or data URI in your ticket PDF, app or email. Fetch the authenticated image endpoint from your backend when needed; do not include your API key in a URL.
  5. At entry, your ticketing backend checks that ticket and atomically marks it redeemed.

Generating a QR code does not confirm a payment or prevent a copied ticket from being reused. Your ticketing system remains responsible for ticket ownership, cancellation and one-time redemption.

ModeScan behavior
Static (default)Encodes your payload directly. Works with raw scanner tokens or validation URLs. Printed codes cannot be edited or tracked by Linkwave. Pausing or deleting the Linkwave record does not invalidate a static ticket.
DynamicEncodes a Linkwave redirect to your HTTP(S) validation URL. Its destination and paused status can be managed in the dashboard. Scans can be tracked. Browser access to the Linkwave redirect is required.

Designs

Choose a template, foreground color, background color, custom frame label, and logo. Use a dark foreground with a light background; the API requires at least 4.5:1 contrast. The size parameter (128-2048, default 720) controls the inner design size; padding and frames add to the final dimensions.

{
  "design": {
    "template": "ticket",
    "label": "ADMIT ONE",
    "foreground": "#16181d",
    "background": "#ffffff",
    "logo": {
      "data_url": "data:image/png;base64,YOUR_BASE64_IMAGE"
    }
  },
  "size": 720
}

Use either { "preset": "calendar" } or { "data_url": "data:image/png;base64,..." } for design.logo. Embedded PNG, JPEG and WebP images can be up to 100 KB decoded. Remote image URLs and uploaded SVG images are not accepted. Logos are self-contained in the returned SVG.

Template IDs

cleanroundedcircle-labellabellabel-darkcircleorbitconfetticircle-soliddouble-framebracketscornersticketscan-stripposter

Logo preset IDs

whatsappinstagramfacebookyoutubetiktokxgooglespotifymenuwi-fireviewchatemailphonedocumentcalendarlocationshopqr-codeheartcontact

Custom labels support up to 28 characters. Choose a label-capable template such as ticket, label-dark, or circle-label to display the label.

Endpoints

MethodPathScopeResponse
POST/api/v1/qr-codesqr:writeCreate QR with styled SVG
GET/api/v1/qr-codes?limit=25&offset=0qr:readPaginated workspace QR codes
GET/api/v1/qr-codes/{id}qr:readQR metadata and saved design
GET/api/v1/qr-codes/{id}/image?size=720qr:readSaved design as image/svg+xml
GET/api/v1/templatesqr:readTemplate and logo preset IDs

The list endpoint accepts a limit of 1-100 and an offset of 0-10,000. Responses include pagination.has_more. Use the QR ID stored with each ticket to retrieve it directly. API-created QR codes also appear in your dashboard. Images containing external dashboard logo URLs cannot be rendered through the API; create API designs with a preset or embedded image.

Retries and limits

POST requires Idempotency-Key: 1-128 printable ASCII characters without spaces. Repeating the same key and normalized request returns HTTP 200 and Idempotency-Replayed: true, with the same QR ID. It returns the current saved QR design. Reusing a key with a different request returns 409. A deleted QR returns 410; it is not silently recreated. Keys are scoped to the workspace and retained for its lifetime.

Requests are limited to 120 per minute per workspace across all its keys. Successful authenticated requests include X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix seconds). A 429 includes Retry-After. Retry 429 and 503 responses with backoff, and retry network failures using the original idempotency key. Retrying does not consume another QR quota slot, but it does count as an API request.

All API-created records, static or dynamic, count toward the workspace QR allowance. Business and Business Plus use a UTC calendar month; deleted QR codes still count for that month. Other API-enabled plans use their total active-record limit. JSON request bodies are limited to 200,000 bytes; payloads are limited to 1024 UTF-8 bytes. Upgrade in Billing when more capacity is needed.

Errors

{
  "error": {
    "code": "qr_quota_exceeded",
    "message": "Workspace QR quota reached. Upgrade your plan",
    "request_id": "be6bba15-ae56-44a8-bc0b-2cbe53cc7bd6"
  }
}
400Invalid JSON or missing idempotency key
401Missing, invalid, expired or revoked key
402Workspace QR quota reached
403Required scope, API plan or active subscription missing
404QR not found in this workspace
409Idempotency key reused with different input
410Previously created QR was deleted
413 / 415Body too large / wrong content type
422Payload, image, design or query validation failed
429Workspace rate limit reached
503Temporary service failure or pending API database migration

Each response includes X-Request-Id. Keep this ID when contacting support. Never include your API key in logs or support messages.