Last month I needed to generate QR codes server-side for a client project. I tried a few existing APIs and... wasn't thrilled. One charged $49/mo for basic features. Another had a 100-request limit before demanding a credit card. Most had SDKs that felt like they were written in 2012.
So I built my own. And then productized it.
The API
Dead simple. One endpoint:
curl "https://api.qrcodeapi.io/generate?data=https://dev.to&size=300"Returns a QR code. That's it.
Options:
-
format- png, svg, or base64 -
size- 100-1000px -
color- hex color for the QR code -
bgColor- hex color for background -
errorCorrection- L, M, Q, or H
Purple QR code on transparent background
curl "https://api.qrcodeapi.io/generate?data=hello&color=8b5cf6&bgColor=transparent&format=svg"## The interesting parts
Dynamic QR Codes
This was the feature I actually needed. Print a QR code on 10,000 flyers, realize the URL has a typo? With static QR codes, you're reprinting.
With dynamic QR codes, the QR points to a redirect URL that you control. Change the destination anytime without reprinting anything.
// Create a dynamic link
const response = await fetch('https://api.qrcodeapi.io/links', {
method: 'POST',
headers: { 'X-API-Key': 'your-key' },
body: JSON.stringify({ url: 'https://example.com/campaign-v1' })
});
// Returns a short code like "abc123"
// QR code points to: https://qr.qrcodeapi.io/abc123
// Later, update the destination:
await fetch('https://api.qrcodeapi.io/links/abc123', {
method: 'PUT',
headers: { 'X-API-Key': 'your-key' },
body: JSON.stringify({ url: 'https://example.com/campaign-v2' })
});### Scan Analytics
Every scan through a dynamic link gets tracked:
- Device type (mobile/tablet/desktop)
- Country & city (via IP geolocation)
- Referrer
- Timestamp
No cookies, no fingerprinting - just basic HTTP request data. Privacy-respecting analytics.
const stats = await fetch('https://api.qrcodeapi.io/analytics/abc123', {
headers: { 'X-API-Key': 'your-key' }
});
// Returns:
// {
// totalScans: 1247,
// uniqueScans: 892,
// byDevice: { mobile: 743, desktop: 401, tablet: 103 },
// byCountry: { US: 521, UK: 234, DE: 189, ... },
// byDay: [{ date: '2025-12-15', scans: 87 }, ...]
// }## Tech Stack
For the curious:
- Runtime: Vercel Serverless Functions
- Database: Supabase (PostgreSQL)
-
QR Generation:
qrcodenpm package -
Image Processing:
sharpfor logo overlays -
Geo-IP:
geoip-lite - Payments: Stripe
The whole thing is ~15 API endpoints consolidated into 9 serverless functions (Vercel Hobby plan has a 12-function limit π ).
TypeScript SDK
Also published an npm package:
npm install qrcode-api-sdk
import { QRCodeAPI } from 'qrcode-api-sdk';
const client = new QRCodeAPI({ apiKey: 'your-key' });
// Generate QR code
const qr = await client.generate({
data: 'https://dev.to',
format: 'svg',
color: '#000000'
});
// Create dynamic link
const link = await client.links.create({
url: 'https://example.com'
});
// Get analytics
const stats = await client.analytics.get(link.shortCode);Full TypeScript types included.
Pricing
- Free: 100 QR/month (no credit card)
- Starter: $9/mo - 5,000 QR/month
- Pro: $29/mo - 50,000 QR/month + analytics + dynamic links
I tried to price it where indie devs can actually afford it. The free tier is enough for most side projects.
What I'd do differently
Start with dynamic QR codes first - That's what people actually pay for. Static QR generation is basically a commodity.
Build the SDK earlier - Having a proper TypeScript SDK with types makes the DX so much better. Should've done this from day one.
Don't underestimate SEO - Half my traffic comes from people googling "QR code API Node.js" or "dynamic QR code API". I spent a weekend building SEO landing pages and it was worth it.
Try it out
- π qrcodeapi.io
- π Documentation
- π¦ npm package
Would love feedback, especially on pricing and what features you'd want to see next. Thinking about adding:
- Bulk generation endpoint (ZIP file with multiple QR codes)
- QR code templates/styles
- Webhook notifications for scan events
Let me know what would be useful! π
Top comments (0)