Platform API v2 · Generally Available

Build on frqr.app

Scoped API tokens, idempotent writes, unified webhooks, and full governance control over QR codes, short links, and physical asset lifecycle — all in one REST API.

Scoped tokens

Each token carries exactly the permissions it needs. 18 fine-grained scopes across assets, governance, lifecycle, crisis, and webhooks.

Idempotent writes

Send an Idempotency-Key header and POST safely — duplicate requests within 24 h return the cached response without creating duplicates.

Unified webhooks

20 event types, one subscription model. HMAC-SHA256 signed payloads, automatic retries with exponential back-off (1 min → 5 min → 15 min → 1 h).

Tier rate limits

Lite 100 req/min · Pro 1 000 req/min · Scale 10 000 req/min · Enterprise 50 000 req/min. Limits surfaced in X-RateLimit-* response headers.

CIDR IP allowlist

Lock tokens to specific IP ranges — individual IPs or CIDR blocks. Requests from unlisted IPs receive 403 before any scope check.

OpenAPI specs

Machine-readable specs at /api/v1/openapi.json and /api/v2/openapi.json. Import into Postman, Insomnia, or any OpenAPI-compatible tool.

Quick start

Make your first authenticated request in under 2 minutes.

1

Create a token

Go to Admin → API Tokens, click New token, choose your scopes, and copy the plain-text token shown once.

frqr_pk_<64-hex-characters>
2

Make a request

Pass the token as a Bearer in the Authorization header.

curl https://frqr.app/api/v2/qr-codes \
  -H "Authorization: Bearer frqr_pk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Product A QR",
    "type": "url",
    "destination": "https://example.com/product-a"
  }'
3

Handle the response

All v2 responses are wrapped in a data key. Errors include a machine-readable error code.

{
  "data": {
    "id": 42,
    "slug": "abc123",
    "scan_url": "https://frqr.app/q/abc123",
    "destination": "https://example.com/product-a",
    "type": "url",
    "created_at": "2026-05-06T12:00:00Z"
  }
}

Token scopes

Grant only the scopes your integration needs — principle of least privilege.

Scope Grants access to
assets:read GET QR codes, short links, bio pages
assets:write POST/PATCH QR codes, short links, bio pages
assets:delete DELETE QR codes, short links, bio pages
change_requests:read List and view change requests
change_requests:write Submit new destination change requests
change_requests:approve Approve, reject, or emergency-override change requests
custodians:read View custodian assignments
custodians:write Assign and remove custodians
batches:read List asset batches
batches:write Create batches
batches:recall Trigger batch recall
lifecycle:read View lifecycle history and current state
lifecycle:write Transition asset lifecycle state
crisis:read View active crisis modes
crisis:write Activate or resolve crisis mode
webhooks:manage Create, update, delete webhook subscriptions
tokens:read List own API tokens
tokens:write Create and revoke own API tokens

Webhooks

Subscribe to platform events and receive real-time HTTP callbacks to your endpoint.

Subscribe

POST /api/v2/webhooks
Authorization: Bearer frqr_pk_...

{
  "url": "https://yourapp.com/hooks/frqr",
  "events": [
    "change_request.approved",
    "asset.lifecycle.transitioned"
  ]
}

Verify signature

// X-Frqr-Signature: sha256=<hmac>
$sig = 'sha256=' . hash_hmac(
    'sha256',
    $rawBody,
    $webhookSecret
);
$valid = hash_equals($sig, $header);

Event catalog

change_request.created
change_request.approved
change_request.rejected
change_request.emergency_approved
qr_code.created
qr_code.updated
qr_code.deleted
short_link.created
short_link.updated
short_link.deleted
asset.health.degraded
asset.health.recovered
asset.health.fallback.triggered
asset.lifecycle.transitioned
batch.recalled
crisis.activated
crisis.resolved

Rate limits

Limits apply per token per minute. Response headers tell you where you stand.

Plan Requests / min Max tokens
Lite1005
Pro1,00020
Scale10,000Unlimited
Enterprise50,000Unlimited

Response headers

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 978
X-RateLimit-Reset: 1715000000
Retry-After: 42 (seconds, on 429 only)

API versions

Both versions coexist — v1 is maintained for backward compatibility, v2 is the recommended path for new integrations.

v1 · Legacy
  • · Authorization: Bearer <token> (plain user token)
  • · Short links, QR codes, change requests
  • · No scopes, no idempotency keys
  • · Spec: /api/v1/openapi.json
Open v1 playground →
v2 · Recommended
  • · Scoped platform tokens (frqr_pk_…)
  • · Full governance: custodians, batches, lifecycle, crisis
  • · Idempotency keys, tier rate limits, CIDR allowlist
  • · Spec: /api/v2/openapi.json
Open v2 playground →

Idempotency

Safe retries on any POST or PATCH request — send the same key within 24 hours to get the same response.

curl -X POST https://frqr.app/api/v2/qr-codes \
  -H "Authorization: Bearer frqr_pk_..." \
  -H "Idempotency-Key: order-9823-qr-create" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Order 9823 QR", "type": "url", "destination": "https://track.example.com/9823" }'

A cached hit returns HTTP 200 with X-Idempotent-Replayed: true. Keys are namespaced per user — you cannot replay another user's key.

Ready to integrate?

Create your first token and make a request in under 2 minutes.