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
| Plan | Codes/Day | API Requests/Min |
|---|---|---|
| Free | 10 | 60 |
| Pro | 100 | 300 |
| Business | 1,000 | 1,200 |
| Enterprise | Unlimited | Custom |
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.