Journal

PromptPay QR Code Generator UI in SwiftUI

Generate the format wrong and no bank app will scan it. The engineering is the payload; the UI is making it scannable.

PromptPay QR Code Generator UI in SwiftUI: a glossy App Store icon on a blue, pink and orange gradient with bubbles

TL;DR

A PromptPay QR generator produces Thailand's national instant-payment receive code (PromptPay launched 2016), and the build is fundamentally about generating a correct, standards-compliant QR: an EMVCo TLV (tag-length-value) payload with the PromptPay ID, THB currency, optional amount, and a CRC checksum, not free text, since a wrong format will not scan in any banking app. The key product decision is static (reusable, no amount) versus dynamic (per-transaction amount baked in), the QR must render large and high-contrast, and the payee and amount must show as readable text beside it as a fraud defense. The app generates the receive code; the payer's bank moves the money. A free VP0 design supplies the receive and amount screens.

What is PromptPay, and what does “generator” mean here?

Thailand’s national instant-payment system, where you receive money by showing a QR code tied to your phone number, citizen ID, or e-wallet instead of sharing bank details. PromptPay launched in 2016 and became how Thailand pays: a merchant or person displays a QR, the payer scans it in their banking app, and money moves instantly. A “PromptPay QR generator” produces that receive-code, optionally with an amount baked in, so the build is fundamentally about generating a correct, standards-compliant QR, not a generic QR with text in it.

The honest framing first: the QR is not free text, it is a structured EMVCo merchant-presented QR payload following the Thai standard, with specific data fields and a checksum. Generate it wrong and no banking app will scan it, so the engineering is encoding the payload to spec, and the UI is making that correct code easy to show and share. A clone that draws a pretty QR encoding the wrong format is a decoration, not a payment code.

How is the payload actually built?

As an EMVCo TLV (tag-length-value) string with a CRC checksum, which is the part that must be exactly right:

FieldWhat it carriesWhy it matters
Payload format / typeStatic (reusable) vs dynamic (one amount)A fixed amount changes the whole code
Merchant account infoThe PromptPay ID (phone, citizen ID, e-wallet)Who gets paid
Currency / countryTHB, ThailandRequired by the standard
Transaction amountOptional; baked in for dynamic QRPayer cannot mistype the amount
CRC checksumValidates the whole payloadA wrong checksum makes the QR unscannable

The static-versus-dynamic distinction is the key product decision: a static QR (no amount) is the reusable code a shop tapes to the counter, the payer types the amount; a dynamic QR encodes a specific amount so the payer just confirms, which is what an invoice or a point-of-sale screen generates per transaction. Getting the TLV structure and the CRC right is non-negotiable, and rendering the QR from that correct string uses Core Image’s QR generator filter at high enough resolution to scan reliably (its error-correction level M can recover roughly 15% of a damaged code, but a clean high-contrast render still matters most).

What does the receive screen owe the user?

Scannability and honest context, because this screen is shown to someone who is about to send money. The QR must render large and high-contrast (a small or low-res QR fails to scan in real lighting, the most common complaint), with the recipient name and, for a dynamic code, the amount shown in plain text beside it so the payer confirms they are paying the right person the right amount before scanning. Showing the amount and payee as readable text next to the QR is itself a fraud-defense: a QR alone is unverifiable to a human, so the human-readable context is how a payer catches a swapped code.

Two more honesties. Save and share: the user wants to send the QR (to a customer over chat) or save it, so a clean export of the code-plus-context is core, the same render-to-share discipline as any QR or share artifact. And the receive side is the app’s job, the pay side is the payer’s banking app, so a generator app is honest that it produces a code to be paid, it does not move the money itself, the same render-the-UI, settle-through-the-licensed-rail framing as every fintech build like the PromptPay-adjacent regional wallets.

What completes a PromptPay generator?

The surrounding flow. Multiple PromptPay IDs (a user may register a phone and a citizen ID), a quick amount entry for dynamic codes, a saved-payees or recent-amounts convenience, and clear handling of the static-vs-dynamic toggle so the user understands which kind of code they are showing. And validation: the app should confirm the PromptPay ID is well-formed before generating, because a code for a mistyped ID looks fine and silently sends money nowhere recoverable.

The screens, the receive screen with the big QR, the amount entry, the ID management, the share, come as a free VP0 design, so an agent builds the EMVCo payload encoder and Core Image rendering onto a UI already shaped for scannable display and human-readable context rather than a generic QR maker.

Key takeaways: a PromptPay QR generator

  • The payload is a standard, not free text: an EMVCo TLV string with a CRC checksum; wrong format means no app will scan it.
  • Static vs dynamic is the key decision: a reusable no-amount code versus a per-transaction code with the amount baked in.
  • Render large and high-contrast: a small or low-res QR failing to scan is the most common real-world complaint.
  • Show payee and amount as text beside the QR: human-readable context is a fraud defense, since a QR alone is unverifiable.
  • Generate the receive code; the payer’s bank moves the money: validate the PromptPay ID, and never imply the app settles funds.

Frequently asked questions

How do I build a PromptPay QR code generator in SwiftUI? Encode an EMVCo TLV payload (payload type, the PromptPay ID, THB currency, optional amount, and a CRC checksum) to the Thai standard, then render it with Core Image’s QR filter at a scannable resolution, showing the payee and amount as text beside the code. A free VP0 design supplies the receive, amount-entry, and ID-management screens.

Why can’t I use a generic QR generator for PromptPay? Because a PromptPay QR is a structured EMVCo merchant-presented payload with specific data fields and a checksum, not arbitrary text. A generic QR encoding the wrong format will not scan in any banking app, so the engineering is producing a standards-compliant payload, and the pretty rendering is the easy part.

What is the difference between a static and dynamic PromptPay QR? A static QR carries no amount and is reusable, the code a shop tapes to the counter where the payer types the amount; a dynamic QR bakes in a specific amount so the payer just confirms, which an invoice or point-of-sale screen generates per transaction. The choice changes the payload, so the app should expose it clearly.

Why must the QR render large and high-contrast? Because a small or low-resolution QR is the most common real-world failure: it will not scan reliably in ordinary lighting on the payer’s phone. Render the code large and high-contrast, and generate it at sufficient resolution, since an unscannable receive code defeats the entire purpose of the screen.

Does a PromptPay generator app move the money? No: it produces the receive code, and the payer’s own banking app scans it and moves the money through the licensed PromptPay rails. An honest generator validates the PromptPay ID and shows readable payee-and-amount context, but it never settles funds itself or implies it does.

More questions from VP0 vibe coders

How do I build a PromptPay QR code generator in SwiftUI?

Encode an EMVCo TLV payload (payload type, the PromptPay ID, THB currency, optional amount, and a CRC checksum) to the Thai standard, then render it with Core Image's QR filter at a scannable resolution, showing the payee and amount as text beside the code. A free VP0 design supplies the receive, amount-entry, and ID-management screens.

Why can't I use a generic QR generator for PromptPay?

Because a PromptPay QR is a structured EMVCo merchant-presented payload with specific data fields and a checksum, not arbitrary text. A generic QR encoding the wrong format will not scan in any banking app, so the engineering is producing a standards-compliant payload, and the pretty rendering is the easy part.

What is the difference between a static and dynamic PromptPay QR?

A static QR carries no amount and is reusable, the code a shop tapes to the counter where the payer types the amount; a dynamic QR bakes in a specific amount so the payer just confirms, which an invoice or point-of-sale screen generates per transaction. The choice changes the payload, so the app should expose it clearly.

Why must a PromptPay QR render large and high-contrast?

Because a small or low-resolution QR is the most common real-world failure: it will not scan reliably in ordinary lighting on the payer's phone. Render the code large and high-contrast, and generate it at sufficient resolution, since an unscannable receive code defeats the entire purpose of the screen.

Does a PromptPay generator app move the money?

No: it produces the receive code, and the payer's own banking app scans it and moves the money through the licensed PromptPay rails. An honest generator validates the PromptPay ID and shows readable payee-and-amount context, but it never settles funds itself or implies it does.

Part of the Native Apple & SwiftUI: The iOS Ecosystem hub. Browse all VP0 topics →

Keep reading

Tikkie Betaalverzoek UI Clone in SwiftUI: Request & Split: a glass photo icon surrounded by chat, music, heart, camera and shopping app icons on a pastel gradient
Guides 5 min read

Tikkie Betaalverzoek UI Clone in SwiftUI: Request & Split

How to build a Tikkie-style payment request UI in SwiftUI: the betaalverzoek composer, share-first flow, who-paid tracker, and kind reminders.

Lawrence Arya · June 5, 2026
Apple External Purchase Link Modal UI in SwiftUI: The Build: a reflective 3D App Store icon on a blue and purple gradient
Guides 6 min read

Apple External Purchase Link Modal UI in SwiftUI: The Build

The link-out door is open but regional: eligibility-gated ExternalPurchaseLink, a trust-handoff modal with visible domain and price, and both paths shipped forever.

Lawrence Arya · June 7, 2026
Klarna Checkout UI Widget in SwiftUI: The Honest Build: a glass iPhone app-grid icon on a mint and teal gradient
Guides 6 min read

Klarna Checkout UI Widget in SwiftUI: The Honest Build

You render the option and the disclosure; Klarna renders the credit. Placements-API numbers, webhook confirmation, and BNPL cost shown, always.

Lawrence Arya · June 7, 2026
RappiPay Card Management UI in SwiftUI: a glass photo icon surrounded by chat, music, heart, camera and shopping app icons on a pastel gradient
Guides 5 min read

RappiPay Card Management UI in SwiftUI

A card-control UI on a licensed issuer: freeze as state not intent, biometric-gated detail reveal, and every control round-tripping to the issuer.

Lawrence Arya · June 7, 2026
Budgeting App SwiftUI Tutorial: Code That Holds Up: a reflective 3D App Store icon on a blue and purple gradient
Guides 5 min read

Budgeting App SwiftUI Tutorial: Code That Holds Up

Build a budgeting app in SwiftUI: the three-entity model, a 10-second transaction add, envelope views without shame, Swift Charts months, and manual-first honesty.

Lawrence Arya · June 5, 2026
Build a Stock Market Heat Map Grid UI in SwiftUI: a glossy App Store icon on a blue, pink and orange gradient with bubbles
Guides 9 min read

Build a Stock Market Heat Map Grid UI in SwiftUI

A market heat map colors and sizes tiles by gain and market cap. Here is how to build the stock market heat map grid in SwiftUI, with an accessible color scale.

Lawrence Arya · June 9, 2026