Skip to main content
QR codes simplify payments by letting customers scan with their banking or wallet app instead of manually typing account details. This guide covers generating QR codes for both PayID (AUD) and crypto addresses.

Overview

QR codes bridge the gap between your app and the customer’s banking/wallet app. A single scan populates all payment fields, eliminating transcription errors.

PayID QR Codes (AUD)

PayID QR codes follow the standard format:
payid:{payIdAddress}
Example: payid:john.doe@example.com When scanned with an Australian banking app, the PayID field is auto-populated and the customer only needs to enter the amount and confirm.

Supported Banks

All major Australian banks support PayID/Osko QR scanning:
BankPayID SupportQR Scanning
Commonwealth BankYesYes
ANZYesYes
NABYesYes
WestpacYesYes
INGYesYes
Macquarie BankYesYes
Bendigo BankYesYes
Suncorp BankYesYes

Implementation

Node.js

// npm install qrcode
const QRCode = require('qrcode');

async function generatePayIdQR(payId) {
  const dataUrl = await QRCode.toDataURL(`payid:${payId}`, {
    type: 'image/png',
    width: 300,
    margin: 2,
    errorCorrectionLevel: 'H',
    color: {
      dark: '#000000',
      light: '#FFFFFF',
    },
  });
  return dataUrl; // data:image/png;base64,iVBORw0KGgo...
}

// Usage in HTML
const qrDataUrl = await generatePayIdQR('john.doe@example.com');
// <img src="{qrDataUrl}" alt="Scan to pay" />

Python

# pip install qrcode[pil]
import qrcode
import base64
from io import BytesIO


def generate_payid_qr_base64(pay_id: str, size: int = 300) -> str:
    """Generate PayID QR code as base64 data URL."""
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_H,
        box_size=10,
        border=2,
    )
    qr.add_data(f"payid:{pay_id}")
    qr.make(fit=True)

    img = qr.make_image(fill_color="black", back_color="white")

    # Resize to target size
    img = img.resize((size, size))

    buffer = BytesIO()
    img.save(buffer, format="PNG")
    buffer.seek(0)

    b64 = base64.b64encode(buffer.read()).decode()
    return f"data:image/png;base64,{b64}"


# Usage
data_url = generate_payid_qr_base64("john.doe@example.com")
# <img src="{data_url}" alt="PayID QR" />

TypeScript / React

// npm install qrcode.react
import { QRCodeSVG } from 'qrcode.react';
import React from 'react';

interface PayIdQRProps {
  payId: string;
  size?: number;
}

export const PayIdQRCode: React.FC<PayIdQRProps> = ({ payId, size = 256 }) => {
  return (
    <div style={{ textAlign: 'center' }}>
      <QRCodeSVG
        value={`payid:${payId}`}
        size={size}
        level="H" // High error correction
        includeMargin={true}
        bgColor="#FFFFFF"
        fgColor="#000000"
      />
      <p style={{ marginTop: 8, fontFamily: 'monospace' }}>{payId}</p>
    </div>
  );
};

Best Practices

AspectRecommendation
FormatAlways use payid: prefix for AUD payments
Error CorrectionHigh (H) level — allows logo overlays and better scan reliability
Minimum Size200×200px for digital display, 2×2cm for print
ColorsHigh contrast (dark on light). Avoid light colors
BorderMinimum 2-4 modules quiet zone around the QR code
ResolutionMinimum 72 DPI for screen, 300 DPI for print
TestingAlways test with actual banking apps before launch

Crypto Address QR Codes

For crypto deposits, use the standard URI format:
{currency}:{address}?network={network}
Example for ERC-20 USDT:
ethereum:0x742d35Cc6634C0532925a3b8D4C9db96590f6C7E?network=ETH
Example for TRC-20 USDT:
tron:TXYZ1234567890...?network=TRX

Simple Crypto QR Generator

const QRCode = require('qrcode');

async function generateCryptoQR(address, network, currency = 'ethereum') {
  const uri = `${currency}:${address}?network=${network}`;
  return QRCode.toDataURL(uri, {
    width: 256,
    margin: 2,
    errorCorrectionLevel: 'M',
  });
}

// Usage
const qr = await generateCryptoQR(
  '0x742d35Cc6634C0532925a3b8D4C9db96590f6C7E',
  'ETH',
  'ethereum'
);

Integration Flow

1

Create VA

Call POST /virtual-account/create with customerId and currency.
2

Extract PayID

From the response, get response.data.payId.
3

Generate QR

Use one of the code examples above to generate a QR code from payid:{payId}.
4

Display in UI

Embed the QR code in your payment page alongside the text PayID and BSB + Account Number.
5

Customer Scans

Customer opens their banking app, scans the QR code, enters the amount, and confirms.
6

Payment Arrives

Your webhook endpoint receives a DEPOSIT_RECEIVED event. Processing begins automatically.

Testing

Verify your QR codes before deploying:
  1. Online scanner: Use an online QR decoder to verify the content matches payid:{address}
  2. Banking app test: Scan with a real Australian banking app (CommBank, ANZ, etc.)
  3. Edge cases: Test with different phone cameras, lighting conditions, and screen sizes

Quick Test Script

# Install zbar-tools (Linux/Mac)
# brew install zbar (Mac)
# apt-get install zbar-tools (Linux)

# Decode a generated QR image
zbarimg --raw payid-qr.png
# Expected output: payid:john.doe@example.com