Back to docs
SDK
JavaScript / TypeScript
The official @qrmax/node SDK — typed, tree-shakeable, works in Node 18+, Bun, Deno, and edge runtimes. Zero dependencies.
100% TypeScriptZero dependenciesESM + CJSEdge runtime compatible
Install
npm install @qrmax/nodeRequires Node.js 18+ (native fetch support). For older Node, install node-fetch and polyfill globally.
Initialize the client
Import and instantiate the client with your API key.
TypeScript
import QRMax from '@qrmax/node';
const qrmax = new QRMax({
apiKey: process.env.QRMAX_API_KEY,
});Create a dynamic QR code
Returns the short URL and the image URL for immediate use.
TypeScript
const qr = await qrmax.qrCodes.create({
type: 'url',
target: 'https://example.com/spring-sale',
dynamic: true,
design: {
foregroundColor: '#4f46e5',
logoUrl: 'https://example.com/logo.png',
cornerStyle: 'rounded',
},
});
console.log(qr.shortUrl); // https://qrx.io/a3b9c2
console.log(qr.imageUrl); // https://cdn.qrmax.io/qr/qr_01HNP....pngRe-target a dynamic QR
The printed pattern never changes — only the redirect does.
TypeScript
await qrmax.qrCodes.update(qr.id, {
target: 'https://example.com/summer-sale',
});Fetch scan analytics
Pass a date range. Returns counts, device breakdown, and geo.
TypeScript
const analytics = await qrmax.qrCodes.analytics(qr.id, {
from: '2026-04-01',
to: '2026-04-19',
});
console.log(analytics.totalScans); // 1247
console.log(analytics.uniqueScanners); // 892
console.log(analytics.topCountries); // [{ code: 'US', scans: 420 }, ...]List and paginate
Use async iteration for automatic pagination across all pages.
TypeScript
for await (const qr of qrmax.qrCodes.list({ type: 'url' })) {
console.log(qr.id, qr.shortUrl);
}Verify a webhook
Validate the HMAC signature before trusting an inbound webhook payload.
TypeScript
import { verifyWebhook } from '@qrmax/node';
app.post('/webhooks/qrmax', (req, res) => {
const signature = req.header('X-QRMax-Signature');
const body = req.rawBody; // raw bytes, not parsed JSON
const valid = verifyWebhook({
body,
signature,
secret: process.env.QRMAX_WEBHOOK_SECRET,
});
if (!valid) return res.status(400).send('invalid signature');
const event = JSON.parse(body.toString());
console.log(event.event, event.data);
res.status(200).send('ok');
});Error handling
Typed errors let you distinguish between network, auth, and validation failures.
TypeScript
import { QRMaxError, RateLimitError } from '@qrmax/node';
try {
await qrmax.qrCodes.create({ type: 'url', target: '' });
} catch (err) {
if (err instanceof RateLimitError) {
console.log(`Retry after ${err.retryAfterMs}ms`);
} else if (err instanceof QRMaxError) {
console.log(err.status, err.code, err.message);
} else {
throw err;
}
}