8 min read API SDK Developer Webhooks

QR Codes for Developers: REST API, SDK and CLI

How to programmatically generate QR codes, integrate them into your app, and react to scans via webhooks — a technical deep-dive.

by qr3.app Team

QR Codes for Developers: REST API, SDK and CLI — qr3.app Blog
8 min read API SDK Developer Webhooks

QR Codes for Developers: REST API, SDK and CLI

How to programmatically generate QR codes, integrate them into your app, and react to scans via webhooks — a technical deep-dive.

by qr3.app Team

As a developer, you don’t want to create QR codes manually through a dashboard — you want to generate them automatically, integrate them into your build pipeline, and react to scans via webhooks. That’s exactly what qr3.app is built for.

The Stack

qr3.app is fully Cloudflare-native:

  • API Worker: Hono on Cloudflare Workers (V8 runtime, zero Node.js dependencies)
  • Redirect Worker: Ultra-lean worker, KV-cached redirects in < 5ms p50
  • Database: Cloudflare D1 (SQLite) with multi-tenancy via workspace_id
  • Queue: Scan events decoupled via Cloudflare Queues

Authentication

All API requests require a Bearer token and a workspace ID:

POST https://qr3.app/v1/codes
Authorization: Bearer qr3_sk_...
Content-Type: application/json

Create API keys at app.qr3.app/dashboard/api-keys.

TypeScript SDK

npm install @qr3/sdk
# or
pnpm add @qr3/sdk
import { QR3 } from "@qr3/sdk";

const client = new QR3({
  apiKey: process.env.QR3_API_KEY!,
  workspaceId: process.env.QR3_WORKSPACE_ID!,
});

// Create a QR code
const { data: code } = await client.codes.create({
  type: "url",
  url: "https://my-shop.com/product/42",
  title: "Product 42",
  tags: ["shop", "product"],
});

console.log(code.short_code);       // "r7f3Kx"
console.log(code.image_svg_url);    // SVG image URL
console.log(code.redirect_url);     // https://qr3.app/r7f3Kx

// Change URL later (dynamic codes only)
await client.codes.update(code.id, {
  url: "https://my-shop.com/product/42-new",
});

// Query analytics
const stats = await client.codes.stats(code.id, {
  from: "2026-01-01",
  to: "2026-03-31",
});
console.log(stats.data.total_scans); // e.g. 1247

REST API Direct

No SDK dependency? The REST API is directly usable:

# Create a QR code
curl -X POST https://qr3.app/v1/codes \
  -H "Authorization: Bearer $QR3_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "url",
    "url": "https://my-site.com",
    "title": "My Site",
    "is_dynamic": true
  }'

# List all QR codes
curl https://qr3.app/v1/codes?limit=20 \
  -H "Authorization: Bearer $QR3_API_KEY"

# Download QR code as SVG (with logo overlay)
curl "https://qr3.app/v1/codes/r7f3Kx/qr.svg?size=8&logo_url=https://mylogo.com/logo.png" \
  -o qrcode.svg

CLI

For scripting and CI/CD there’s the @qr3/cli:

npm install -g @qr3/cli
qr3 login

# Create QR code and save as SVG
qr3 codes create --url "https://my-site.com" --title "CI Deploy" --output qr.svg

# Batch creation from CSV
qr3 codes batch import urls.csv --format svg --output ./qr-codes/

Webhooks: React to Scans

Webhooks are the most powerful feature: you can react in real-time to every scan.

// Register a webhook
const { data: webhook } = await client.webhooks.create({
  url: "https://your-app.com/webhooks/qr3",
  events: ["scan.created", "code.updated"],
});

Webhook Payload

{
  "event": "scan.created",
  "timestamp": "2026-03-15T14:30:00Z",
  "data": {
    "code_id": "code_abc123",
    "short_code": "r7f3Kx",
    "country": "DE",
    "city": "Berlin",
    "device": "mobile",
    "os": "iOS",
    "browser": "Safari"
  }
}

Verify Webhooks (HMAC)

import { createHmac } from "crypto";

export async function verifyWebhook(
  payload: string,
  signature: string,
  secret: string,
): Promise<boolean> {
  const expected = createHmac("sha256", secret)
    .update(payload)
    .digest("hex");
  return `sha256=${expected}` === signature;
}

Rate Limiting

PlanCodes/DayAPI Requests/Min
Free1060
Pro100300
Business1,0001,200
EnterpriseUnlimitedCustom

Rate limit headers in every response:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 247
X-RateLimit-Reset: 1710510060

Error Format (RFC 7807)

All errors follow RFC 7807 Problem Details:

{
  "type": "https://docs.qr3.app/errors/validation",
  "title": "Validation Error",
  "status": 422,
  "detail": "url is required for type 'url'",
  "errors": [
    { "field": "url", "message": "Required" }
  ]
}

Conclusion

qr3.app is built from the ground up as a developer tool: open REST API, TypeScript-first SDK, CLI, webhooks and complete OpenAPI documentation. Check out the API documentation or get started in the Dashboard.