Quickstart
Your first QRdx API request in under two minutes, with no key. Then dynamic codes with an access token.
The QRdx API has two halves. Images need nothing: no account, no key. Dynamic codes, scans and webhooks belong to an account, so they need an access token.
Make a QR code (no key)
Run this. It saves a PNG of a QR code that opens qrdx.dev:
curl "https://api.qrdx.dev/v1/qr?data=https://qrdx.dev&format=png" -o qr.pngThat's a working API call. The URL itself is the image, so it also works straight in an <img> tag:
<img src="https://api.qrdx.dev/v1/qr?data=https://qrdx.dev&fg=111111&body=circle" alt="QR code for qrdx.dev" />Change the colors, shapes, size and format with query parameters, or try them in the browser on the Render a QR code image page: its Try it panel sends the request and shows the image. Images don't count against any quota; the limit is 300 requests a minute per IP address.
Get an access token
Everything else in the API acts on an account: create dynamic codes, change where they point, read their scans. Those requests carry an access token in the Authorization header.
API keys aren't available yet
Today, the only way to get a token is to register an OAuth app and sign in through it once. It takes about five minutes the first time. When API keys ship, this whole step becomes "create a key in Settings → Developers", and every request below works unchanged with the key in place of the token. API keys below will say when.
-
Register an app. In Settings → Developers, choose New app. Give it a name, add the redirect URI
http://localhost:8787/callback, and select the scopescodes:read,codes:writeandprofile:read. Copy the client ID and the client secret (the secret is shown once). -
Sign in through it. Save this script as
get-token.mjs. It runs the OAuth flow with PKCE against your own account and prints your tokens. It needs Node 18 or later and nothing else:get-token.mjs import { createHash, randomBytes } from "node:crypto"; import { createServer } from "node:http"; const clientId = process.env.QRDX_CLIENT_ID; const clientSecret = process.env.QRDX_CLIENT_SECRET; const redirectUri = "http://localhost:8787/callback"; const verifier = randomBytes(32).toString("base64url"); const challenge = createHash("sha256").update(verifier).digest("base64url"); const state = randomBytes(16).toString("hex"); const authorize = new URL("https://qrdx.dev/api/oauth/authorize"); authorize.search = new URLSearchParams({ response_type: "code", client_id: clientId, redirect_uri: redirectUri, scope: "codes:read codes:write profile:read", state, code_challenge: challenge, code_challenge_method: "S256", }); console.log(`Open this URL and approve your app:\n\n${authorize}\n`); const server = createServer(async (req, res) => { const url = new URL(req.url, redirectUri); if (url.pathname !== "/callback") return res.writeHead(404).end(); const code = url.searchParams.get("code"); if (!code || url.searchParams.get("state") !== state) { res.writeHead(400).end(url.searchParams.get("error") ?? "Bad callback"); return; } const response = await fetch("https://qrdx.dev/api/oauth/token", { method: "POST", body: new URLSearchParams({ grant_type: "authorization_code", client_id: clientId, client_secret: clientSecret, code, redirect_uri: redirectUri, code_verifier: verifier, }), }); const tokens = await response.json(); res.end(response.ok ? "Done: back to your terminal." : "Failed: see your terminal."); server.close(); console.log(tokens); }); server.listen(8787);QRDX_CLIENT_ID=... QRDX_CLIENT_SECRET=... node get-token.mjsOpen the URL it prints, approve your app, and the terminal shows
access_tokenandrefresh_token. -
Keep it handy. Export the access token for the next step:
export QRDX_TOKEN=...
Access tokens last one hour; the refresh token gets you a new one for 30 days (refreshing tokens). Requests made with a token act on your personal workspace and count against its daily quota (1,000 requests on Free).
Create a dynamic code
A dynamic code is a short link you can point somewhere else after it's printed:
curl -X POST https://api.qrdx.dev/v1/codes \
-H "Authorization: Bearer $QRDX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"destinationUrl": "https://example.com", "title": "My first code"}'The response is 201 Created with the new code:
{
"data": {
"id": "cm5code0spring0menu00001",
"slug": "aB3dE5f",
"shortLink": "https://qrdx.dev/q/aB3dE5f",
"destinationUrl": "https://example.com/",
"title": "My first code",
"status": "active",
"scanCount": 0
}
}(Shortened: Create codes shows every field.) The QR code encodes shortLink. Render it with the image API from step 1, https://api.qrdx.dev/v1/qr?data=https://qrdx.dev/q/aB3dE5f, and print it.
Point it somewhere else
Change the destination at any time; the printed code keeps working:
curl -X PATCH https://api.qrdx.dev/v1/codes/$CODE_ID \
-H "Authorization: Bearer $QRDX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"destinationUrl": "https://example.com/new-page"}'Scan the code once, then read its analytics with GET /v1/codes/$CODE_ID/scans (Get scan analytics).
When something goes wrong
Every error is JSON with a stable code and a message that says what to do:
{
"code": "UNAUTHORIZED",
"message": "Missing access token. Send an OAuth access token as \"Authorization: Bearer <token>\". …",
"status": 401
}The errors page lists every code with its fix.
API keys
API keys don't exist yet. Until they do, use an OAuth access token as in step 2; they authenticate the same requests. When keys ship, this section will show how to create one, and the Authorization: Bearer header will take either.
Next steps
Last updated on