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 base64size- 100-1000pxcolor- hex color for the QR codebgColor- hex color for backgrounderrorCorrection- L, M, Q, or H
Purple QR code on transparent background
curl ...
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 base64size- 100-1000pxcolor- hex color for the QR codebgColor- hex color for backgrounderrorCorrection- 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. 1.
Build the SDK earlier - Having a proper TypeScript SDK with types makes the DX so much better. Should’ve done this from day one. 1.
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
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! 🙏