Skip to main content

QR Code Generator API

REAL DATA

Scannable ISO/IEC 18004 QR codes as SVG — L/M/Q/H error correction, custom module size, quiet zone and colours, byte-identical for a given request URL.

Authoritative reference data or standards computation

Base URL
/api/qr-codes
Capabilities
2 routes
Last updated
July 29, 2026
Data source

GET /api/qr-codes/image

Returns the symbol itself (image/svg+xml), not JSON. Modules are drawn in module coordinates with a viewBox, so the image stays crisp at any size.

Live requestRuns against the public API
No key required
GET/api/qr-codes/image?data=https%3A%2F%2Frandomapi.dev

Request parameters

Payload to encode, 1–900 characters. Encoded verbatim — leading and trailing spaces are preserved, and nothing is fetched, resolved or checked for where it points.

Error-correction level: L recovers ~7% of codewords, M ~15%, Q ~25%, H ~30%. Higher levels survive more damage but need a larger symbol for the same payload.

Pixels per module (1–16). The image is square: (modules + 2 × quietZone) × scale pixels.

Light border in modules (0–8). ISO/IEC 18004 requires 4; smaller values are out of spec and may fail to scan.

Module colour as 3- or 6-digit hex, with or without a leading '#'. Must differ from bg.

Background colour as 3- or 6-digit hex, with or without a leading '#'. Must differ from fg.

Encoding mode. 'auto' picks numeric when every character is a digit, alphanumeric when every character is in the 45-character QR set, otherwise byte. Forcing a mode the payload cannot use returns 400.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
<img src="https://randomapi.dev/api/qr-codes/image?data=https%3A%2F%2Frandomapi.dev" alt="Generated image" />
curl -o image.svg "https://randomapi.dev/api/qr-codes/image?data=https%3A%2F%2Frandomapi.dev"
const res = await fetch("https://randomapi.dev/api/qr-codes/image?data=https%3A%2F%2Frandomapi.dev");
const svg = await res.text();
import requests

svg = requests.get("https://randomapi.dev/api/qr-codes/image?data=https%3A%2F%2Frandomapi.dev").text
Parameters Route-specific request inputs 7
data string required

Payload to encode, 1–900 characters. Encoded verbatim — leading and trailing spaces are preserved, and nothing is fetched, resolved or checked for where it points.

allowed: 1 – 900
example: data=https://randomapi.dev
ecc enum

Error-correction level: L recovers ~7% of codewords, M ~15%, Q ~25%, H ~30%. Higher levels survive more damage but need a larger symbol for the same payload.

default: M
allowed: L | M | Q | H
example: ecc=H
scale int

Pixels per module (1–16). The image is square: (modules + 2 × quietZone) × scale pixels.

default: 4
allowed: 1 – 16
example: scale=8
quietZone int

Light border in modules (0–8). ISO/IEC 18004 requires 4; smaller values are out of spec and may fail to scan.

default: 4
allowed: 0 – 8
example: quietZone=2
fg string

Module colour as 3- or 6-digit hex, with or without a leading '#'. Must differ from bg.

default: 000000
allowed: ≤ 7
example: fg=1a1a1a
bg string

Background colour as 3- or 6-digit hex, with or without a leading '#'. Must differ from fg.

default: ffffff
allowed: ≤ 7
example: bg=f5f5f4
mode enum

Encoding mode. 'auto' picks numeric when every character is a digit, alphanumeric when every character is in the 45-character QR set, otherwise byte. Forcing a mode the payload cannot use returns 400.

default: auto
allowed: auto | numeric | alphanumeric | byte
example: mode=byte

Documented examples

Build-generated requests and complete responses
4
QR code for a URL
GET /api/qr-codes/image?data=https%3A%2F%2Frandomapi.dev
QR code for a URL
High error correction, larger modules
GET /api/qr-codes/image?data=https%3A%2F%2Frandomapi.dev%2Fapis&ecc=H&scale=8
High error correction, larger modules
Custom colours and a tight quiet zone
GET /api/qr-codes/image?data=https%3A%2F%2Frandomapi.dev%2Fdocs&fg=1a1a1a&bg=f5f5f4&quietZone=2
Custom colours and a tight quiet zone
Numeric payload in numeric mode
GET /api/qr-codes/image?data=8675309&mode=numeric
Numeric payload in numeric mode

GET /api/qr-codes/info

Runs the same encoder as /image and reports the chosen version, module count, mask pattern and the capacity left at every error-correction level — without transferring an image.

Live requestRuns against the public API
No key required
GET/api/qr-codes/info?data=https%3A%2F%2Frandomapi.dev

Request parameters

Payload to encode, 1–900 characters. Encoded verbatim — leading and trailing spaces are preserved, and nothing is fetched, resolved or checked for where it points.

Error-correction level: L recovers ~7% of codewords, M ~15%, Q ~25%, H ~30%. Higher levels survive more damage but need a larger symbol for the same payload.

Encoding mode. 'auto' picks numeric when every character is a digit, alphanumeric when every character is in the 45-character QR set, otherwise byte. Forcing a mode the payload cannot use returns 400.

Advanced response options4 options

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/qr-codes/info?data=https%3A%2F%2Frandomapi.dev"
const res = await fetch("https://randomapi.dev/api/qr-codes/info?data=https%3A%2F%2Frandomapi.dev");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/qr-codes/info?data=https%3A%2F%2Frandomapi.dev").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/qr-codes/info?data=https%3A%2F%2Frandomapi.dev"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 3
data string required

Payload to encode, 1–900 characters. Encoded verbatim — leading and trailing spaces are preserved, and nothing is fetched, resolved or checked for where it points.

allowed: 1 – 900
example: data=https://randomapi.dev
ecc enum

Error-correction level: L recovers ~7% of codewords, M ~15%, Q ~25%, H ~30%. Higher levels survive more damage but need a larger symbol for the same payload.

default: M
allowed: L | M | Q | H
example: ecc=H
mode enum

Encoding mode. 'auto' picks numeric when every character is a digit, alphanumeric when every character is in the 45-character QR set, otherwise byte. Forcing a mode the payload cannot use returns 400.

default: auto
allowed: auto | numeric | alphanumeric | byte
example: mode=byte
Universal parameters Shared response and formatting options 4
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=version,modules
exclude list

Return all fields except these (comma-separated).

example: exclude=svgHeight
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 12
version integer (1-40)

Smallest QR version whose data capacity fits the payload at this level.

example: 2

modules integer

Modules per side of the symbol, excluding the quiet zone (4 × version + 17).

example: 25

eccLevel string (L | M | Q | H)

Error-correction level used for the calculation.

example: M

mode string (numeric | alphanumeric | byte)

Encoding mode actually applied after 'auto' resolution.

example: byte

capacityBits integer

Data-codeword capacity of this version and level, in bits (error-correction codewords excluded).

example: 224

dataBits integer

Bits the segment occupies: 4-bit mode indicator + character-count indicator + payload.

example: 180

remainderBits integer (0 | 3 | 4 | 7)

Symbol bits left over once whole codewords are placed; encoded as zero, then masked like any other data module.

example: 7

maskPattern integer (0-7)

Data mask chosen by scoring all eight patterns with the four penalty rules.

example: 4

capacityByLevel object

Maximum characters this version holds in the selected mode at each level (UTF-8 bytes in byte mode): { L, M, Q, H }.

example: {"L":32,"M":26,"Q":20,"H":14}

quietZoneModules integer

Quiet zone the /image route applies by default, in modules.

example: 4

svgWidth integer

Width in pixels /image returns at its default scale=4 and quietZone=4.

example: 132

svgHeight integer

Height in pixels /image returns at its default scale=4 and quietZone=4 (always equal to svgWidth).

example: 132

Documented examples

Build-generated requests and complete responses
3
What version does this URL need?
GET /api/qr-codes/info?data=https%3A%2F%2Frandomapi.dev
{
  "data": {
    "version": 2,
    "modules": 25,
    "eccLevel": "M",
    "mode": "byte",
    "capacityBits": 224,
    "dataBits": 180,
    "remainderBits": 7,
    "maskPattern": 5,
    "capacityByLevel": {
      "L": 32,
      "M": 26,
      "Q": 20,
      "H": 14
    },
    "quietZoneModules": 4,
    "svgWidth": 132,
    "svgHeight": 132
  },
  "meta": {
    "endpoint": "qr-codes",
    "route": "/info",
    "params": {
      "data": "https://randomapi.dev",
      "ecc": "M",
      "mode": "auto"
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
Capacity headroom at high error correction
GET /api/qr-codes/info?data=https%3A%2F%2Frandomapi.dev%2Fapis&ecc=H
{
  "data": {
    "version": 4,
    "modules": 33,
    "eccLevel": "H",
    "mode": "byte",
    "capacityBits": 288,
    "dataBits": 220,
    "remainderBits": 7,
    "maskPattern": 2,
    "capacityByLevel": {
      "L": 78,
      "M": 62,
      "Q": 46,
      "H": 34
    },
    "quietZoneModules": 4,
    "svgWidth": 164,
    "svgHeight": 164
  },
  "meta": {
    "endpoint": "qr-codes",
    "route": "/info",
    "params": {
      "data": "https://randomapi.dev/apis",
      "ecc": "H",
      "mode": "auto"
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
Force byte mode for a numeric payload
GET /api/qr-codes/info?data=8675309&mode=byte
{
  "data": {
    "version": 1,
    "modules": 21,
    "eccLevel": "M",
    "mode": "byte",
    "capacityBits": 128,
    "dataBits": 68,
    "remainderBits": 0,
    "maskPattern": 3,
    "capacityByLevel": {
      "L": 17,
      "M": 14,
      "Q": 11,
      "H": 7
    },
    "quietZoneModules": 4,
    "svgWidth": 116,
    "svgHeight": 116
  },
  "meta": {
    "endpoint": "qr-codes",
    "route": "/info",
    "params": {
      "data": "8675309",
      "ecc": "M",
      "mode": "byte"
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}

About this API

Coverage & behavior

Returns a real, scannable QR symbol as SVG (Content-Type: image/svg+xml), encoded to ISO/IEC 18004 — Reed-Solomon error correction over GF(256), the standard block interleaving, BCH-protected format and version information, and full evaluation of all eight data masks. Drop it straight into an <img src>; the same URL always returns a byte-identical image and is served with long cache headers, so it is safe to hotlink.

Two routes. /image renders the symbol. /info answers the sizing questions without downloading an image: which version the payload needs, how many modules that is, the mask that scored best, and how much room is left at each error-correction level.

Encoding mode is a documented rule, never a guess. mode=auto (the default) picks numeric when every character is a digit, alphanumeric when every character is in the 45-character QR set (0-9 A-Z, space, $ % * + - . / :), and byte otherwise. Force a mode with mode=; a payload the mode cannot represent returns 400 naming the offending character and its position, and nothing is ever truncated.

Version selection takes the smallest version (1–40) whose data capacity at the chosen level fits the bit stream, and the response is a 400 stating the exact limit for that mode and level if nothing fits. The 900-character cap bounds the symbol differently at each level, because byte mode is measured in UTF-8 bytes rather than characters: at level L it tops out at version 39 (173 × 173 modules, 2,809 bytes), while at M, Q and H a multi-byte payload does reach version 40 (177 × 177) — the format's largest symbol — from 738 three-byte characters at M, 527 at Q and 407 at H.

Error correction. ecc=L|M|Q|H recovers roughly 7%, 15%, 25% and 30% of codewords respectively. Higher levels are more robust on damaged or curved surfaces but push the payload into a larger symbol.

Rendering. scale sets pixels per module (1–16, default 4), quietZone the light border in modules (0–8, default 4 — the standard's minimum; smaller values are out of spec and may not scan), and fg/bg the module and background colours as 3- or 6-digit hex. Dark-on-light with strong contrast is what scanners expect; identical fg and bg are rejected.

Scope and honesty. This endpoint encodes only — there is no decoder or scanner here. Output is SVG only; there is no raster route, so it is not a fit for HTML email, where the major clients strip or ignore SVG <img> sources. Byte mode emits UTF-8 without an ECI designator, the de-facto convention that modern readers auto-detect; ISO/IEC 18004 nominally defaults byte mode to ISO/IEC 8859-1, so a strict reader may interpret non-ASCII bytes differently. Kanji mode, ECI segments, structured append, multi-segment optimisation and Micro QR are not implemented, and there are no logo overlays or artistic QR styles — an overlay silently spends the error-correction budget this page quotes, so we will not claim a recovery rate we no longer control. The module matrix is correct, but whether a given print or screen actually scans also depends on physical size, resolution and contrast, which we cannot control. The 900-character limit counts UTF-16 code units, so characters outside the Basic Multilingual Plane (most emoji) count as two.

Your payload is public. It travels in the query string, so it is logged, cached and visible to every proxy, mail filter and URL scanner on the path — which is exactly why this endpoint adds no obfuscation value to a phishing link: the destination is readable without decoding the symbol. Do not encode passwords, tokens or anything else secret.

QR Code is a registered trademark of DENSO WAVE INCORPORATED. This is an independent implementation of the published ISO/IEC 18004 symbology, not affiliated with or endorsed by the trademark holder.

Use it for

  • Print scannable URL, Wi-Fi or vCard QR codes on tickets, labels and packaging
  • Embed a QR code in a web page, PDF invoice or print template with a plain <img src> and no build step
  • Check which version and error-correction level a payload needs before sending artwork to print
  • Generate deterministic QR fixtures for camera and scanner integration tests

Frequently asked questions

Is there a free QR code API without an API key?

Yes — GET /api/qr-codes/image?data=... returns an SVG with no key, no signup and no watermark. The image is a pure function of the URL, so it is cached hard and safe to hotlink from your own pages.

How much data fits in one QR code?

At version 40 the ceiling is 7,089 digits, 4,296 alphanumeric characters or 2,953 bytes at level L, dropping to 3,057 / 1,852 / 1,273 at level H. This endpoint accepts up to 900 characters and returns 400 with the exact limit if the payload cannot fit.

Which error correction level should I use?

M (the default) is the usual choice for screens and clean print. Use Q or H for labels that get scratched, curved or partly covered, and L only when you need to squeeze a long payload into a smaller symbol.

Can I change the QR code size and colours?

Yes — scale sets pixels per module (1–16), quietZone the light border in modules (0–8), and fg/bg take 3- or 6-digit hex. The SVG is vector, so it also scales losslessly after the fact; /info reports the pixel size you will get at the defaults.

Do you check or resolve the link I encode?

No — we never fetch, resolve, expand or check where the payload points. The only validation is structural: its length against the 900-character cap, whether the chosen mode can represent every character, and whether the bytes fit a version-40 symbol. It also adds no obfuscation, because the destination sits in plain text in the image URL, so any mail filter or link scanner reads it without decoding the symbol.

Standards & references