paynow_qr

Gem Version CI License: MIT

Generate EMVCo-compliant Singapore PayNow (SGQR) QR payloads in pure Ruby. Zero runtime dependencies — pair with any QR renderer (rqrcode, chunky_png, or your platform of choice).

Why

Ruby was the only major ecosystem missing a clean PayNow library. Every other runtime has one (paynowqr on npm, pyPayNowSg on PyPI, etc.). This is the Ruby port.

Install

# Gemfile
gem "paynow_qr"
bundle install
# or
gem install paynow_qr

Quick start

require "paynow_qr"

payload = PaynowQR.generate(
  proxy_type:  :uen,
  proxy_value: "201234567A",
  amount:      25.00,
  company:     "ACME PTE LTD",
  reference:   "INV-001"
)
# => "00020101021126..."

Render it as an image with your favourite QR gem:

require "rqrcode"

png = RQRCode::QRCode.new(payload).as_png(size: 512)
File.binwrite("paynow.png", png.to_s)

API

PaynowQR.generate(**opts) / PaynowQR::Generator.new(**opts).payload

Option Type Default Description
proxy_type :uen, :mobile, or "0".."9" required PayNow proxy type.
proxy_value String required UEN (e.g. "201234567A") or mobile with country code ("+6591234567").
amount Numeric, String, nil nil SGD amount. Omit for an any-amount QR.
editable Boolean false If true, the QR is dynamic — the amount is omitted from the payload and entered at payment time.
company String "NA" Merchant name (max 25 chars per EMVCo).
expiry Date, Time, String, nil today + 1 year Expiry as a Date/Time, or "YYYYMMDD" string.
reference String, nil nil Optional bill / invoice reference.

Returns the EMVCo payload String. Pass it to any QR renderer.

Proxy types

Symbol Code Notes
:mobile 0 Include country code (+65…).
:uen 2 Standard Singapore UEN.

You can pass a single-digit string (e.g. "3") if you need a proxy type not covered by the symbols above — this library does not restrict future codes.

Examples

Fixed-amount UEN QR

PaynowQR.generate(
  proxy_type:  :uen,
  proxy_value: "201234567A",
  amount:      49.90,
  company:     "ACME PTE LTD"
)

Any-amount mobile QR

PaynowQR.generate(
  proxy_type:  :mobile,
  proxy_value: "+6591234567",
  company:     "Jane Doe"
)

Editable-amount QR with expiry

PaynowQR.generate(
  proxy_type:  :uen,
  proxy_value: "201234567A",
  amount:      100.00,
  editable:    true,
  expiry:      Date.new(2026, 12, 31),
  reference:   "ORDER-42"
)

Specification

This library implements the EMVCo Merchant Presented Mode QR Code specification and the MAS SGQR / PayNow specification.

Field layout:

ID Name Notes
00 Payload Format Indicator Always 01
01 Point of Initiation Method 11 static (fixed amount), 12 dynamic
26 Merchant Account Info (PayNow) See sub-fields below
52 Merchant Category Code 0000 (unused by PayNow)
53 Currency 702 (SGD)
54 Transaction Amount Omitted for dynamic QRs
58 Country Code SG
59 Merchant Name
60 Merchant City Singapore
62 Additional Data Contains sub-field 01 (reference)
63 CRC CRC-16/CCITT-FALSE

Sub-fields under 26:

ID Name Value
00 AID SG.PAYNOW
01 Proxy Type 0 (mobile) / 2 (UEN)
02 Proxy Value UEN or mobile
03 Editable Flag 0 (fixed) / 1 (editable)
04 Expiry YYYYMMDD

Development

bin/setup
bundle exec rspec
bundle exec rubocop

Install locally:

bundle exec rake install

Contributing

Bug reports and PRs are welcome at https://github.com/ryzs/paynow_qr. Before opening a PR please run bundle exec rake and add tests.

License

Released under the MIT License.