Quickstart
Generate your first QR code with QR Code Agency in five minutes.
Quickstart
Generate your first QR code in five minutes. By the end of this page, you will have a PNG on disk, you will know how to add a logo, and you will know how to check your remaining quota.
Before you start
You will need:
- An API key starting with
smk_(see Authentication) - An HTTP client (curl, Postman, your language of choice)
info: Base URL Production:
https://api.qrstudio.agencyLocal development:http://localhost:8000
Examples below use the production host. Swap if you are running the backend locally.
Step 1: Make your first call
Generate a 4 inch black QR on a white background pointing at
https://example.com.
cURL
curl -X POST https://api.qrstudio.agency/api/v1/generate/ \
-H "X-Api-Key: smk_REPLACE_WITH_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": "https://example.com",
"size_inches": 4,
"color": "black",
"background": "white"
}' \
--output my-first-qr.pngPython
import requests
r = requests.post(
"https://api.qrstudio.agency/api/v1/generate/",
headers={"X-Api-Key": "smk_REPLACE_WITH_YOUR_KEY"},
json={
"data": "https://example.com",
"size_inches": 4,
"color": "black",
"background": "white",
},
timeout=30,
)
r.raise_for_status()
with open("my-first-qr.png", "wb") as f:
f.write(r.content)
print("Saved to my-first-qr.png")JavaScript
const r = await fetch("https://api.qrstudio.agency/api/v1/generate/", {
method: "POST",
headers: {
"X-Api-Key": "smk_REPLACE_WITH_YOUR_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
data: "https://example.com",
size_inches: 4,
color: "black",
background: "white",
}),
});
if (!r.ok) throw new Error(`HTTP ${r.status}`);
// In a browser: display it
const url = URL.createObjectURL(await r.blob());
document.querySelector("img").src = url;Node.js
import fs from "node:fs";
const r = await fetch("https://api.qrstudio.agency/api/v1/generate/", {
method: "POST",
headers: {
"X-Api-Key": "smk_REPLACE_WITH_YOUR_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({ data: "https://example.com", size_inches: 4 }),
});
fs.writeFileSync("my-first-qr.png", Buffer.from(await r.arrayBuffer()));Open my-first-qr.png. You should see a clean QR code. Scan it with your
phone, the camera opens example.com.
success: What just happened You sent a JSON payload describing the QR. We rendered it server-side at 1200 x 1200 px (4 inches x 300 DPI), embedded ERROR_CORRECT_H so it stays scannable, ran it through the render cache, and returned the PNG bytes. The headers
X-QR-Cache,X-QR-Plan, andX-QR-Quota-Remainingtell you the rest.
Step 2: Add a logo
Drop your brand logo into the center. ERROR_CORRECT_H gives you up to 30% obstruction tolerance, so a logo at the default 24% size is always scannable.
cURL
curl -X POST https://api.qrstudio.agency/api/v1/generate/ \
-H "X-Api-Key: smk_REPLACE_WITH_YOUR_KEY" \
-F "data=https://example.com" \
-F "size_inches=4" \
-F "color=black" \
-F "background=white" \
-F "logo_file=@/path/to/your/logo.png" \
--output qr-with-logo.pngPython
import requests
with open("logo.png", "rb") as logo:
r = requests.post(
"https://api.qrstudio.agency/api/v1/generate/",
headers={"X-Api-Key": "smk_REPLACE_WITH_YOUR_KEY"},
data={
"data": "https://example.com",
"size_inches": 4,
"color": "black",
"background": "white",
},
files={"logo_file": logo},
timeout=60,
)
r.raise_for_status()
open("qr-with-logo.png", "wb").write(r.content)note: Logo limits
- Maximum file size: 2 MB
- Maximum dimensions: 1024 x 1024 px (auto downscaled if larger)
- PNG with transparent background works best
- Custom logos require Starter plan or higher
Step 3: Try a different data type
QR codes encode more than URLs. Generate a one-tap Wi-Fi join QR for your cafe:
curl -X POST https://api.qrstudio.agency/api/v1/generate/ \
-H "X-Api-Key: smk_REPLACE_WITH_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"data_type": "wifi",
"payload": {
"ssid": "Cafe WiFi",
"password": "WelcomeGuest2026",
"auth": "WPA"
},
"size_inches": 4,
"format": "svg"
}' \
--output cafe-wifi.svgWhen customers scan it, their phone offers to join your network with no password typing. See Data types for vCard, geo, email, SMS, and more.
Step 4: Make it dynamic
Static QRs encode a URL forever. Dynamic QRs encode a short URL we host: once printed, you can repoint the destination any time.
curl -X POST https://api.qrstudio.agency/api/v1/generate/ \
-H "X-Api-Key: smk_REPLACE_WITH_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"data_type": "dynamic",
"payload": {
"name": "Spring 2026 menu",
"destination_url": "https://example.com/menus/spring-2026"
},
"size_inches": 4
}' \
--output menu-qr.pngThe PNG you get back encodes https://q.qrstudio.agency/q/<short_id>/.
Print it. Six months later, change the destination from your dashboard,
no reprint required. See Static vs dynamic
for the trade-offs.
Step 5: Check your usage
You have a monthly quota. Read it with:
curl https://api.qrstudio.agency/api/v1/usage/ \
-H "X-Api-Key: smk_REPLACE_WITH_YOUR_KEY"{
"key_prefix": "smk_aBc1",
"plan": "starter",
"monthly_quota": 500,
"used_this_month": 12,
"remaining": 488,
"max_size_inches": 8,
"max_dpi": 300,
"allow_custom_logo": true,
"max_active_dynamic_qrs": 10,
"max_bulk_items": 50
}The same numbers come back as response headers on every successful
/generate/ call (X-QR-Quota-Remaining, X-QR-Plan).
Common pitfalls
warning: 401 Unauthorized Your
X-Api-Keyheader is missing or wrong. Make sure the key starts withsmk_and has not been revoked.
warning: 403 Forbidden Your plan does not allow what you asked for. Examples:
- Free caps
size_inchesat 3 - Free and Starter cap
dpiat 300 - Free does not allow custom logos
- Free does not allow bulk generation
See Plans and limits for the full table.
warning: 429 Too Many Requests You used your monthly quota. On Starter and Pro, overage is allowed and billed per unit; on Free and Enterprise, you wait for the 1st of next month or upgrade.
What is next
Manage your keys: rotate, revoke, scope per environment.
vCard, Wi-Fi, email, SMS, geo, and dynamic encoding rules.
Colors, gradients, eye shapes, frames, transparent backgrounds.
Every parameter, every response code, every header.