AnvilJSON utilities

Anvil › Docs › /v1/qr.svg

QR code SVG API: encode text as a scannable SVG image

Need a QR code you can drop straight into a page or email? Pass the text and get back an SVG. Use the URL as an <img src>, or fetch it from a script. Same generator as Tooltern's browser QR tool — including the error-correction levels that let a centre logo survive.

In one line: GET /v1/qr.svg?text=hello&ec=M returns image/svg+xml. No key, CORS on, 60 requests a minute.
GET

/v1/qr.svg

QR code as SVG (usable as an <img src>). Change the values and press Send request to call the live API.

Parameters

NameTypeWhat it doesDefault
text requiredstringPayload to encode (URL or text), up to 1200 UTF-8 bytes—
ecstringError correction: L≈7%, M≈15%, Q≈25%, H≈30%M
borderintegerQuiet-zone modules, 1–82
boxintegerModule size 1–20 (affects SVG millimetre scale)10
fgstringDark-module hex colour like 000000 or #1f6f5c—
bgstringLight-module / background hex colour—

Example

Request:

GET https://api.oddlathe.com/v1/qr.svg?text=hello&ec=M

Response (generated by the real code when these docs were last built):

<?xml version='1.0' encoding='UTF-8'?>
<svg width="25mm" height="25mm" version="1.1" viewBox="0 0 25 25" xmlns="http://www.w3.org/2000/svg"><rect fill="#ffffff" x="0" y="0" width="100%" height="100%" /><path d="M2,2H3V3H2zM3,2H4V3H3zM4,2H5V3H4zM5,2H6V3H5zM6,2H7V3H6zM7,2H8V3H7zM8,2H9V3H8zM11,2H12V3H11zM12,2H13V3H12zM16,2H17V3H16zM17,2H18V3H17zM18,2H19V3H18zM19,2H20V3H19zM20,2H21V3H20zM21,2H22V3H21zM22,2H23V3H22zM2,3H3V4H2zM8,3H9V4H8zM10,3H11V4H10zM11,3H12V4H11zM16,3H17V4H16zM22,3H23V4H22zM2,4H3V5H2zM4,4H5V5H4zM5,4H6V5H5zM6,4H7V5H6zM8,4H9V5H8zM11,4H12V5H11
 …

Code examples

curl
curl 'https://api.oddlathe.com/v1/qr.svg?text=hello&ec=M'
JavaScript (browser or Node 18+)
const params = new URLSearchParams({
  text: "hello",
  ec: "M"
});
const res = await fetch(`https://api.oddlathe.com/v1/qr.svg?${params}`);
if (!res.ok) throw new Error((await res.json()).error.message);
const data = await res.json();
console.log(data);
Python (standard library only)
import json, urllib.parse, urllib.request

params = urllib.parse.urlencode({"text": "hello", "ec": "M"})
url = "https://api.oddlathe.com/v1/qr.svg?" + params
# Send a User-Agent: the edge network refuses Python's default one.
req = urllib.request.Request(url, headers={"User-Agent": "my-script/1.0"})
with urllib.request.urlopen(req, timeout=10) as r:
    data = json.load(r)
print(data)

When it's useful

  • Embedding a scannable link in docs, emails or static sites without a tracking redirect
  • CI or build scripts that need a deterministic SVG for a URL
  • Teaching how error correction (L/M/Q/H) lets a QR code survive damage or a centre logo
  • Brand-coloured codes via <code>fg</code> / <code>bg</code> hex colours

Good to know

  • Response Content-Type is image/svg+xml — not JSON. Point an <img> at the URL, or use the JSON twin /v1/qr when you need the SVG as a string.
  • text is required, max 1200 UTF-8 bytes. Longer payloads need more modules; if encoding fails, shorten the text or drop to a lower ec.
  • ec is error correction: L ≈7%, M ≈15% (default), Q ≈25%, H ≈30%. Higher levels survive more damage (and centre logos) but make denser codes.
  • border (1–8, default 2) is the quiet-zone modules around the code. box (1–20, default 10) scales module size in the SVG (10 ≈ 1 mm per module).
  • fg / bg accept 3- or 6-digit hex with or without # (encode # as %23). Keep contrast high — pale-on-pale codes often will not scan.
  • Text travels in the URL. Don't encode secrets. Nothing is stored or logged.
  • Browser UI: Tooltern QR code generator (logo preview, SVG/PNG download). How error correction works: Wirebook device heat / QR centre-logo demo and the Tooltern QR not scanning guide.

Encode text into a QR code and return image/svg+xml. Same generator as Tooltern's /api/qr and /qr-code page. Text travels in the URL — don't put secrets here. Nothing is stored or logged.

Errors

Errors are JSON like {"error": {"code": "…", "message": "…"}}. The ones this endpoint can return:

  • missing_param (400): a required parameter is missing or empty
  • bad_param (400): a value is the wrong type or out of range (the message says which)
  • too_long (413): text is over 1200 bytes
  • rate_limited (429): over 60 requests a minute; wait for Retry-After seconds

Questions

Do these QR codes expire?

No. The content is in the code itself; there is no redirect that can be switched off.

Why would a phone fail to scan it?

Usually too small on screen/print, low contrast, missing quiet zone, or a centre logo that covers more than the chosen ec can rebuild. Try H, a larger box, and a white border.

Is there a JSON version?

Yes — <code>/v1/qr</code> returns the same SVG inside a JSON object, plus version/module metadata.

Is anything stored?

Never. Generation only; the text is not logged.

Related endpoints

Prefer a page to an API?

Published · OpenAPI 3.1 spec · Limits and privacy