Qrop logoQrop

API documentation

Generate branded QR codes at scale over a simple REST API. All endpoints are versioned under /api/v1 and return JSON.

Authentication

All requests require a Bearer token API key in the Authorization header. Create and manage keys in your dashboard under /dashboard/api-keys. Keys are shown once at creation, so store them securely.

Authorization: Bearer qrop_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx

Keys are created in your dashboard. API access requires an active API plan; see the pricing page for available plans.

Error codes

Errors return a JSON body of the form { "error": "..." } with an appropriate HTTP status.

401Missing or invalid API key.
402Credits exhausted or no active subscription.
400Malformed request (e.g. batch outside 1–25 items).
422Invalid data type, format, resolution, logo, or colours with insufficient contrast to stay scannable.
429Per-second burst or per-minute sustained rate limit exceeded. See the Retry-After header for when to retry.
Rate limits

Each API key is limited independently per plan. Both windows are enforced in parallel, so a 429 fires if either is exceeded. Check the Retry-After header for the reset time.

PlanReq / secReq / minMax resolution
Starter51001 024px
Pro154002 048px
Growth251 0002 048px
Enterprise1005 0004 096px
post/api/v1/generate

Generate a single QR code. Consumes 1 credit.

FieldTypeDescription
datastringrequiredContent to encode (URL, text, vCard string, etc.).
typestringrequiredOne of: url, text, vcard, wifi, email, sms, phone, geo.
formatstringrequiredpng, svg, or pdf.
resolutionnumberrequiredSquare size in px, 1–4096. Plan caps: 1024px Starter · 2048px Pro/Growth · 4096px Enterprise. Returns 422 if exceeded.
foregroundColorstringoptionalHex colour, default #000000.
backgroundColorstringoptionalHex colour, default #FFFFFF.
finderColorstringoptionalHex colour for the finder (corner) patterns.
logoUrlstringoptionalFetched server-side, max 2MB, PNG/JPEG/WebP only. Forces error correction to H.
logoDataUrlstringoptionalInline base64 image (data:image/png;base64,..., jpeg, or webp), max 2MB, PNG/JPEG/WebP only. Use this to upload a logo directly instead of hosting it at a fetchable URL. Takes precedence over logoUrl if both are sent.
errorCorrectionstringoptionalL, M, Q, or H. Auto-upgraded to H when a logo is present.
moduleShapestringoptionalsquare (default), dots, or rounded: shape of the data modules.
finderShapestringoptionalsquare (default), rounded, or circle: shape of the three finder (corner) patterns.
imageRoundnessnumberoptionalOuter corner radius of the whole QR image as a fraction of its resolution (0–0.5, default 0).

Request

{
  "data": "https://example.com",
  "type": "url",
  "format": "png",
  "resolution": 1024,
  "foregroundColor": "#000000",
  "backgroundColor": "#FFFFFF"
}

Response 200

{
  "id": "gen_a1b2c3",
  "image": "data:image/png;base64,iVBORw0KG...",
  "format": "png",
  "resolution": 1024,
  "creditsConsumed": 1
}

Example request

curl -X POST https://www.qrop.co.za/api/v1/generate \
  -H "Authorization: Bearer qrop_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "data": "https://example.com",
    "type": "url",
    "format": "png",
    "resolution": 1024
  }'
post/api/v1/generate/batch

Generate up to 25 QR codes in one request. Each item consumes 1 credit; credits are reserved for the full batch up front (no partial processing).

FieldTypeDescription
itemsarrayrequired1–25 items, each with data and type (see /api/v1/generate).
formatstringrequiredpng, svg, or pdf: applies to every item in the batch.
resolutionnumberrequiredSquare size in px, 1–4096: applies to every item. Same plan caps as /api/v1/generate.
logoUrlstringoptionalFetched once and applied to every item in the batch, max 2MB, PNG/JPEG/WebP only. Not supported with svg format.
logoDataUrlstringoptionalInline base64 image, same logo applied to every item. Takes precedence over logoUrl if both are sent.

The batch logo is per-request, not per-item. Use separate batch calls (or /api/v1/generate) if items need different logos.

Request

{
  "items": [
    { "data": "https://example.com/1", "type": "url" },
    { "data": "https://example.com/2", "type": "url" }
  ],
  "format": "png",
  "resolution": 512,
  "logoUrl": "https://example.com/company-logo.png"
}

Response 200

{
  "results": [
    { "id": "gen_x1_0", "image": "data:image/png;base64,...", "success": true },
    { "id": "gen_x2_1", "image": "data:image/png;base64,...", "success": true }
  ],
  "creditsConsumed": 2,
  "failedCount": 0
}

Example request

curl -X POST https://www.qrop.co.za/api/v1/generate/batch \
  -H "Authorization: Bearer qrop_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "data": "https://example.com/1", "type": "url" },
      { "data": "https://example.com/2", "type": "url" }
    ],
    "format": "png",
    "resolution": 512
  }'

A batch with 0 or more than 25 items returns 400.

Generating large volumes? Items in a batch are rendered one at a time server-side, so a bigger batch size wouldn't generate any faster; it would just mean a slower call and a larger response body. For volumes beyond one batch, issue multiple 25-item batch calls in parallel from your client instead, staying within your plan's rate limit (see /api/v1/usage and the Rate limits section above).

get/api/v1/usage

Return current period usage, remaining allocation, carried credits from previous periods, and your rate limits.

Response 200

{
  "plan": "growth",
  "currentPeriodStart": "2026-06-01T00:00:00Z",
  "currentPeriodEnd": "2026-07-01T00:00:00Z",
  "includedCredits": 50000,
  "includedCreditsUsed": 12450,
  "carriedCredits": 8200,
  "overageCredits": 0,
  "overageCostZar": 0,
  "rateLimit": { "requestsPerSecond": 25, "requestsPerMinute": 1000 }
}

Example request

curl https://www.qrop.co.za/api/v1/usage \
  -H "Authorization: Bearer qrop_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
post/api/v1/keys/rotate

Rotate the calling API key. A new key is returned (shown once); the old key keeps working for a 24-hour grace period before it stops.

Response 200

{
  "newKey": "qrop_live_yyyyyyyyyyyyyyyyyyyy",
  "oldKeyValidUntil": "2026-06-25T10:00:00Z"
}

Example request

curl -X POST https://www.qrop.co.za/api/v1/keys/rotate \
  -H "Authorization: Bearer qrop_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Tracked / dynamic QR codes

Point a QR code at a Qrop-owned redirect URL instead of the destination directly, so scans get logged and the destination stays editable after printing. Registered-only, one extra credit per code. In development, not yet available on your account. Check back or watch the tracking guide for details on how it will work.

Common questions

Why am I getting a 402 error?

A 402 means your API key has no active plan, or your included credits, free allocation, and purchased balance are all exhausted for the current period. Check /api/v1/usage for your current standing, or upgrade your plan on the pricing page.

How do I raise my rate limit?

Rate limits are tied to your API plan, see the Rate limits table above for the per-second and per-minute caps on each tier. Upgrading to a higher plan raises both limits immediately; there is no separate rate limit purchase.

Why did my request return a 422 instead of generating a QR code?

422 means the request was understood but rejected before any credit was consumed, usually an invalid data type or format, a resolution above your plan's cap, or a foreground/background colour combination with too little contrast to scan reliably. The error message states the specific reason.

Can I use the same API key for the web dashboard and the API?

API keys are for the REST API only, they authenticate requests to /api/v1/*. The web dashboard at qrop.co.za uses your regular account login, not an API key.

What happens to in-flight requests when I rotate a key?

The old key keeps working for a 24-hour grace period after rotation, so requests already using it won't break immediately. Update your integration to the new key within that window before the old one stops authenticating.

We use strictly necessary cookies to run Qrop, and (only with your consent) advertising cookies. See our privacy policy for details.