QR Codes API
Create, manage, and track QR codes that open WhatsApp conversations with prefilled messages, perfect for marketing, support, and customer engagement.
Official Documentation: WhatsApp QR Codes API
Overview
The QR Codes API enables QR code generation and management:
- Create QR Codes: Generate QR codes with prefilled messages
- List QR Codes: Retrieve all QR codes for your phone number
- Get QR Details: Fetch specific QR code information
- Update QR Codes: Modify existing QR code messages
- Delete QR Codes: Remove QR codes you no longer need
- Track Usage: Monitor QR code scan metrics
Endpoints
POST /{PHONE_NUMBER_ID}/message_qrdlsGET /{PHONE_NUMBER_ID}/message_qrdlsGET /{PHONE_NUMBER_ID}/message_qrdls/{QR_CODE_ID}POST /{PHONE_NUMBER_ID}/message_qrdlsDELETE /{PHONE_NUMBER_ID}/message_qrdls/{QR_CODE_ID}Important Notes
Quick Start
import WhatsApp from 'meta-cloud-api';
const client = new WhatsApp({ accessToken: process.env.CLOUD_API_ACCESS_TOKEN!, phoneNumberId: Number(process.env.WA_PHONE_NUMBER_ID), businessAcctId: process.env.WA_BUSINESS_ACCOUNT_ID,});
// Create QR code with imageconst qr = await client.qrCode.createQrCode({ prefilled_message: 'Hello! I need support.', generate_qr_image: 'PNG',});
console.log('QR Code URL:', qr.qr_image_url);console.log('Deep Link:', qr.deep_link_url);
// List all QR codesconst allQrCodes = await client.qrCode.getQrCodes();
// Update QR code messageawait client.qrCode.updateQrCode({ code: qr.code, prefilled_message: 'Hi! I have a question.',});
// Delete QR codeawait client.qrCode.deleteQrCode(qr.id);Create QR Code
Generate a new QR code with a prefilled message.
Create with Image
const qrCode = await client.qrCode.createQrCode({ prefilled_message: 'Hello! I scanned your QR code.', generate_qr_image: 'PNG',});
console.log(qrCode);// {// code: 'QRCODE123',// prefilled_message: 'Hello! I scanned your QR code.',// deep_link_url: 'https://wa.me/message/QRCODE123',// qr_image_url: 'https://...'// }Create without Image (Deep Link Only)
const qrCode = await client.qrCode.createQrCode({ prefilled_message: 'Support request from website',});
// Use deep_link_url to generate QR code with your own toolconsole.log('Deep link:', qrCode.deep_link_url);Marketing Campaign QR Code
const marketingQR = await client.qrCode.createQrCode({ prefilled_message: 'PROMO2024 - I want to learn more about the special offer!', generate_qr_image: 'PNG',});
// Download and use qr_image_url in marketing materialsconsole.log('Download QR:', marketingQR.qr_image_url);Support QR Code
const supportQR = await client.qrCode.createQrCode({ prefilled_message: 'I need help with my account', generate_qr_image: 'PNG',});
// Place on support page or print for in-store supportList QR Codes
Retrieve all QR codes for your phone number.
const qrCodes = await client.qrCode.getQrCodes();
qrCodes.forEach(qr => { console.log(`ID: ${qr.id}`); console.log(`Message: ${qr.prefilled_message}`); console.log(`Link: ${qr.deep_link_url}`); console.log('---');});Get QR Code Details
Fetch information about a specific QR code.
const qrCode = await client.qrCode.getQrCode('QR_CODE_ID');
console.log(qrCode);// {// id: 'QR_CODE_ID',// code: 'QRCODE123',// prefilled_message: 'Hello!',// deep_link_url: 'https://wa.me/message/QRCODE123',// qr_image_url: 'https://...'// }Update QR Code
Modify the prefilled message of an existing QR code.
// Update using the code stringawait client.qrCode.updateQrCode({ code: 'QRCODE123', prefilled_message: 'Updated message text',});
// Generate new image after updateconst updated = await client.qrCode.getQrCode('QR_CODE_ID');console.log('Updated QR:', updated.qr_image_url);Delete QR Code
Remove QR codes you no longer need.
await client.qrCode.deleteQrCode('QR_CODE_ID');
console.log('QR code deleted');Use Cases and Examples
1. Product Registration QR Code
async function createProductQRCode(productId: string) { const qr = await client.qrCode.createQrCode({ prefilled_message: `Register product ${productId}`, generate_qr_image: 'PNG', });
// Save QR code info to database await database.products.update(productId, { qrCodeId: qr.id, qrImageUrl: qr.qr_image_url, });
return qr;}2. Event Check-in QR Code
async function createEventQRCode(eventName: string, date: string) { return await client.qrCode.createQrCode({ prefilled_message: `Check-in for ${eventName} on ${date}`, generate_qr_image: 'PNG', });}3. Restaurant Table QR Codes
async function createTableQRCodes(tableCount: number) { const qrCodes = [];
for (let i = 1; i <= tableCount; i++) { const qr = await client.qrCode.createQrCode({ prefilled_message: `Hi! I'm at Table ${i} and I'd like to order.`, generate_qr_image: 'PNG', });
qrCodes.push({ table: i, qrCode: qr }); }
return qrCodes;}4. Customer Feedback QR Code
async function createFeedbackQRCode() { return await client.qrCode.createQrCode({ prefilled_message: 'I have feedback about my recent purchase', generate_qr_image: 'PNG', });}5. Real Estate Property QR Codes
async function createPropertyQRCode(propertyId: string, address: string) { return await client.qrCode.createQrCode({ prefilled_message: `I'm interested in the property at ${address} (ID: ${propertyId})`, generate_qr_image: 'PNG', });}Track QR Code Usage
Monitor which QR codes are being used.
// Store QR code info when createdinterface QRCodeRecord { id: string; code: string; purpose: string; createdAt: Date; scans: number;}
// When receiving messages via webhookapp.post('/webhook', async (req, res) => { const message = req.body.entry[0]?.changes[0]?.value?.messages[0];
if (message?.text?.body) { // Check if message matches any QR code prefilled text const qrCode = await findQRCodeByMessage(message.text.body);
if (qrCode) { // Increment scan counter await incrementQRCodeScans(qrCode.id);
console.log(`QR code ${qrCode.code} was scanned`); } }
res.sendStatus(200);});Response Formats
Create QR Code Response
{ code: 'QRCODE123ABC', prefilled_message: 'Hello! I scanned your QR code.', deep_link_url: 'https://wa.me/message/QRCODE123ABC', qr_image_url: 'https://lookaside.fbsbx.com/...png' // Only if generate_qr_image: 'PNG'}List QR Codes Response
{ data: [ { id: '123', code: 'QR1', prefilled_message: 'Message 1', deep_link_url: 'https://wa.me/message/QR1' }, { id: '456', code: 'QR2', prefilled_message: 'Message 2', deep_link_url: 'https://wa.me/message/QR2' } ]}Get QR Code Response
{ id: '123', code: 'QRCODE123', prefilled_message: 'Hello!', deep_link_url: 'https://wa.me/message/QRCODE123', qr_image_url: 'https://lookaside.fbsbx.com/...png'}Error Handling
try { await client.qrCode.createQrCode({ prefilled_message: 'Hello', generate_qr_image: 'PNG', });} catch (error) { if (error.response) { const { code, message } = error.response.data.error;
switch (code) { case 131000: console.error('Invalid prefilled message content'); break; case 100: console.error('Invalid parameter'); break; default: console.error(`Error ${code}: ${message}`); } }}Best Practices
-
Use Descriptive Messages: Make the purpose clear
// ✅ Goodprefilled_message: 'I need help with my order #12345'// ❌ Badprefilled_message: 'Hi' -
Include Context in Messages: Help identify the source
// ✅ Good - includes contextprefilled_message: 'Support request from product page - Battery issue'// ❌ Less useful - no contextprefilled_message: 'I need help' -
Generate Images for Physical Use: Always use PNG for print
// For printed materials, flyers, etc.const qr = await client.qrCode.createQrCode({prefilled_message: 'Event registration',generate_qr_image: 'PNG', // ✅ Get image}); -
Track and Organize QR Codes: Maintain a database
interface QRCodeCampaign {qrCodeId: string;campaign: string;location: string;createdAt: Date;}await database.qrCodes.insert({qrCodeId: qr.id,campaign: 'Summer Sale 2024',location: 'Store Front',createdAt: new Date(),}); -
Update Instead of Delete: Preserve analytics
// ✅ Update existing QR codesawait client.qrCode.updateQrCode({code: existingQR.code,prefilled_message: 'Updated campaign message',});// ❌ Avoid creating duplicates// await client.qrCode.createQrCode({ ... }); -
Clean Up Unused QR Codes: Regular maintenance
async function cleanupOldQRCodes() {const allQRs = await client.qrCode.getQrCodes();const oldQRs = allQRs.filter(isOlderThan90Days);for (const qr of oldQRs) {await client.qrCode.deleteQrCode(qr.id);}}
Message Format Tips
- Keep messages concise (under 100 characters recommended)
- Include tracking codes or campaign IDs when needed
- Make the message actionable
- Avoid special characters that might not render well
- Test messages before printing QR codes
// Good message examples'Support: Order #12345''SALE2024 - I want the 20% discount''Table 5 - Ready to order''Register warranty for Product ABC''Event check-in: Tech Conference 2024'Related Documentation
- Messages API - Handle incoming messages from QR scans
- Webhooks - Receive QR code scan notifications
- Marketing Guide - QR code marketing strategies
- Analytics - Track QR code performance
Source Code
View the source code on GitHub: QrCodeApi.ts