BPAY โ Bill Payment System
Overviewโ
BPAY is Australia's bill payment scheme that allows customers to pay bills electronically using a Biller Code and a Customer Reference Number (CRN). It operates over the BECS infrastructure and is one of the highest-volume payment methods in Australia.
- Operator: BPAY Group (subsidiary of AusPayNet)
- Launched: 1997
- Volume: ~1 billion transactions per year
- Infrastructure: Built on BECS Direct Entry
- Availability: Payments initiated 24/7; processing next business day
How BPAY Worksโ
Customer (Payer)
โ
โ 1. Gets bill with:
โ - Biller Code (4-6 digits)
โ - CRN (up to 20 digits)
โ - Amount
โ
โ 2. Logs into banking app / phone banking
โ 3. Selects "Pay Bill" โ enters Biller Code + CRN + Amount
โ
โผ
Customer's Bank (Financial Institution)
โ
โ 4. Validates Biller Code against BPAY register
โ 5. Validates CRN format (Luhn check variant)
โ 6. Debits customer account
โ 7. Batches into BPAY file
โ
โผ
BPAY Clearing (via BECS)
โ
โ 8. Files submitted by 5 PM cut-off
โ 9. BPAY clears and routes to biller's bank
โ
โผ
Biller's Bank
โ
โ 10. Credits biller's account
โ 11. Provides remittance file to biller
โ (Biller Code + CRN + Amount + Date)
โ
โผ
Biller (Creditor)
โ
โ 12. Matches CRN to invoice / customer record
โ 13. Marks invoice as paid
BPAY Key Identifiersโ
Biller Codeโ
- 4 to 6 digit number assigned by BPAY
- Uniquely identifies the biller organisation
- Registered in the BPAY biller directory
- Printed on every bill/invoice
Example: Biller Code 12345 = AGL Energy
Customer Reference Number (CRN)โ
- Up to 20 digits
- Set by the biller; unique per customer or invoice
- Contains a check digit (mod-10 Luhn variant)
- Printed alongside Biller Code on the bill
Examples:
Account-based CRN: Customer account number
Invoice-based CRN: Invoice number
Property-based CRN: Property ID + check digit
CRN Validation (Luhn-like check)โ
public boolean validateCrn(String crn) {
// BPAY uses a Luhn variant (weight pattern 1,3,7,9...)
int[] weights = {1, 3, 7, 9};
int sum = 0;
for (int i = 0; i < crn.length() - 1; i++) {
sum += Character.getNumericValue(crn.charAt(i))
* weights[i % 4];
}
int checkDigit = (10 - (sum % 10)) % 10;
return checkDigit == Character.getNumericValue(
crn.charAt(crn.length() - 1));
}
BPAY File Formatโ
BPAY uses a proprietary flat file based on BECS DE format with BPAY-specific extensions:
Record Type 0 โ File Header
Record Type 2 โ BPAY Credit Transaction
Fields:
โโโ BSB (biller's bank BSB)
โโโ Account (biller's account)
โโโ Amount (in cents)
โโโ Biller Code
โโโ CRN (Customer Reference Number)
โโโ Payment date
โโโ Lodgement reference
Record Type 7 โ File Trailer (net totals)
BPAY Processing Windowsโ
| Event | Time (AEST) |
|---|---|
| Payment initiated by customer | 24/7 |
| Bank submission cut-off | 5:00 PM |
| BPAY clearing & routing | Overnight |
| Credit to biller's account | Next business day AM |
| Remittance file to biller | Next business day AM |
Important: Payments made after 5 PM are processed the next business day. Some banks apply a "same-day BPAY" service for payments before a specific intraday cut-off (e.g., 2 PM).
BPAY vs NPP vs Direct Debitโ
| Feature | BPAY | NPP / Osko | BECS Direct Debit |
|---|---|---|---|
| Initiator | Customer (push) | Customer (push) | Biller (pull) |
| Speed | Next business day | < 15 seconds | Next business day |
| Identifier | Biller Code + CRN | PayID / BSB+Account | BSB + Account |
| Remittance | Biller Code + CRN | 280 chars free text | Lodgement ref |
| Dispute window | 7 days | N/A | 7 days |
| Bill-specific | โ Yes | โ Generic | โ Generic |
BPAY Remittance to Billerโ
After clearing, the biller receives a remittance file containing:
For each payment:
- Biller Code
- CRN (Customer Reference Number) โ key for matching to invoice
- Amount paid
- Payment date
- Customer's bank BSB
- Processing date
The biller's accounts receivable system must match these records to open invoices using the CRN.
BPAY Viewโ
BPAY View is an e-billing extension that allows billers to present digital bills directly in customers' banking apps:
Biller generates bill
โ [Electronic bill via BPAY View]
โผ
Customer sees bill in banking app
โ Biller Code, CRN, amount pre-filled
โผ
Customer clicks "Pay" (no manual data entry)
โ
โผ
Standard BPAY payment flow
BPAY Error & Exception Codesโ
| Code | Description |
|---|---|
01 | Invalid Biller Code |
02 | Invalid CRN |
03 | Amount mismatch (if biller restricts amount) |
04 | Biller not accepting payments |
05 | Duplicate payment |
06 | Account closed / invalid |
Java Spring Integration Notesโ
@Service
public class BpayPaymentService {
public BpayPaymentResult processPayment(BpayPaymentRequest request) {
// 1. Validate Biller Code
BillerDetails biller = billerRegistry
.findByCode(request.getBillerCode())
.orElseThrow(() -> new InvalidBillerCodeException(request.getBillerCode()));
// 2. Validate CRN check digit
if (!crnValidator.validate(request.getCrn())) {
throw new InvalidCrnException(request.getCrn());
}
// 3. Validate amount (some billers restrict to exact amount)
if (biller.isFixedAmount() &&
!biller.getFixedAmount().equals(request.getAmount())) {
throw new AmountMismatchException();
}
// 4. Check balance
accountService.checkSufficientFunds(
request.getDebtorAccountId(), request.getAmount());
// 5. Debit customer account
String ledgerRef = ledgerService.postDebit(
request.getDebtorAccountId(), request.getAmount(),
"BPAY " + request.getBillerCode() + " " + request.getCrn());
// 6. Add to BPAY batch for clearing
bpayBatchService.addToBatch(BpayBatchItem.builder()
.billerCode(request.getBillerCode())
.crn(request.getCrn())
.amount(request.getAmount())
.billerBsb(biller.getBsb())
.billerAccount(biller.getAccountNumber())
.build());
return BpayPaymentResult.success(ledgerRef);
}
}
Related Conceptsโ
- outbound.md โ BPAY is an outbound payment
- direct_debit.md โ Pull-based alternative for recurring bills
- npp.md โ Real-time alternative for one-off payments
- clearing.md โ BPAY clears via BECS infrastructure
- reconciliation.md โ CRN-based remittance matching