const logo = await uc.assets.upload(fs.createReadStream('logo.png'), { purpose: 'qr_logo' });
const qr = await uc.qrCodes.create({
type: 'upi',
name: 'Counter 1 — UPI',
payload: { vpa: 'brand@upi', payee_name: 'Brand India Pvt Ltd' },
design: {
foreground_color: '#1A1A2E',
module_shape: 'rounded',
eye_shape: 'rounded',
logo: { asset_id: logo.id, size_ratio: 0.2 },
frame: { style: 'label', text: 'Pay here' },
error_correction: 'H', // with a logo we raise it to at least Q (ratio ≤ 0.2) or H; never lowered
},
});
console.log(qr.render_urls.pdf); // print-ready, cacheable URL
console.log(qr.render_urls.svg);render_urlsare public, unguessable and cached; hand them straight to your print shop or embed them in an<img>. vCard and UPI images contain contact or payee details, so they are cached for at most a day (1 hour in browsers), and a deleted static vCard or UPI code is removed from our CDN cache.- The QR encodes
qr.short_url, so you can change the destination later (PATCH /v1/qr-codes/{id}with a newpayload) without reprinting. - Authenticated renders with design overrides:
GET /v1/qr-codes/{id}.png?size=2048&foreground_color=%23000000(size512, 1024, 2048 or 4096; other values answer400 invalid_query). A render that is not ready within 8 seconds answers503withRetry-After: 2; retry after that delay. - Every saved QR code, static or dynamic, counts toward the plan's QR quota (
403 plan_limit_reached,param: dynamic_qr_total); a dynamic code's short link also counts towardlinks_per_month. - Logo, gradient, eye colour, eye shapes other than
square, theclassymodule style and frames (label,badge,speech,card,crop_corner) need Starter or above (403 feature_not_in_plan,param: qr_brand_kit). Logos must be PNG, JPEG or WebP, up to 2 MB, 4096 × 4096 px and 16 megapixels. Uploads are processed one at a time: if another upload is being processed you get429 rate_limited(param: burst) withRetry-After: 2; retry after that delay. - Every design is scan-tested when it is rendered, not when it is saved. A design that does not scan reliably is still saved, but its renders answer
422 qr_unreadable; raise the contrast or remove the logo and update the design. - A scanned dynamic UPI code shows a payee confirmation page before opening the UPI app; a dynamic vCard code shows a contact card with Save contact.
- Deleting a QR code keeps its short link working unless you pass
?delete_link=true. - A link that has a QR code keeps its slug: renaming it answers
409 state_conflict(param: slug), because printed codes encode the short URL. - Wi-Fi codes have
render_urls: null: the image contains the network password, so download it only through the authenticatedGET /v1/qr-codes/{id}.png(also.svg,.pdf), which answersCache-Control: private, no-store. Test-mode codes are not rendered (409 state_conflict). - A static code cannot change its payload (
422 validation_failed,details[].code: immutable_static_payload); create a new code instead. A vCardwebsiteis checked like a link destination (422 destination_blockedordestination_invalid,param: payload.website). - Changing a link's
destination_urlalso updatespayload.urlof its dynamic URL QR code; the render URLs stay the same. - The link of a dynamic UPI or vCard code has
landing_kindset; change its content on the QR code (PATCH /v1/links/{id}withdestination_urlanswers422,details[].code: qr_landing_link). - Scan analytics:
GET /v1/qr-codes/{id}/stats.