Skip to content

Testing NFC

Prepare a terminal's NFC sticker and check that an iPhone reads it — with a real sticker, or without one by emulating the tag on an Android phone. Time: 20–40 minutes. You need: a registered terminal (with its url), an NTAG213/215/216 sticker or an Android phone with NFC, and an iPhone with NFC (XS or later).

What happens on the phone

On an iPhone with Gerege App (iOS build 122+), reading the sticker opens https://geregeapp.mn/pay/t/<code> as a Universal Link: the app opens, claims the terminal's open basket and shows the payment sheet (the machine's name, location, amount) → Face ID. Inside the app, the QR button's "Scan NFC" reads it too. Without the app, Safari opens the public terminal page (what GET /api/v1/miniapp/pay/t/{code} answers, below). Only the app's owner and its test users are offered the test basket. No phone: simulate-tap.

What to write

The sticker carries only the terminal's URL — never an amount, a secret or a basket:

https://geregeapp.mn/pay/t/<code>

<code> is the 10 characters the server issued (23456789abcdefghjkmnpqrstuvwxyz) and never changes; it is ready in the terminal object's url field (Objects). Put the same URL in the sticker's QR — QR and NFC enter the same way.

The NDEF message is one URI record (TNF 0x01 well-known, type U, URI prefix 0x04 = https://):

D1 01 <payload length> 55 04  67 65 72 65 67 65 61 70 70 2E 6D 6E 2F 70 61 79 2F 74 2F <code bytes>
                              g  e  r  e  g  e  a  p  p  .  m  n  /  p  a  y  /  t  /

Writing a real sticker

  1. An NTAG213 (144 bytes — plenty for this URL), NTAG215 or NTAG216 sticker; for a metal surface an anti-metal sticker (with a ferrite layer).
  2. With Gerege App (iOS build 122+): Settings → Wallet → "Merchants and organisations" → "Write sticker" — a member of your organisation (the console's miniapp.read) picks the terminal from the list; the app writes the canonical URL, reads it back and, once it matches, locks it for good. Or any NFC writing app (NFC Tools, for example) → «Write» → «URL/URI» → the URL above. Print QR stickers from the console's sticker PDF (POST /terminals/print-sheet) — Terminals and NFC stickers.
  3. After writing, lock the tag («Lock tag» / read-only) — an unlocked tag can be overwritten by anyone with another link. Locking cannot be undone; check the URL first, then lock.
  4. Check with an iPhone: screen on (locked or unlocked), with Camera, Wallet / Apple Pay and any other NFC reader inactive, hold the top of the phone to the sticker (background tag reading) — a link notification appears.

Without a sticker: emulating the tag on Android (HCE)

Android's Host Card Emulation turns the phone into an NFC Forum Type 4 Tag, and the iPhone reads its NDEF URI by background tag reading — an easy way to test the URL and the flow before printing stickers. Open-source «HCE NDEF emulator» sample apps exist; if you write your own, the HostApduService answers these APDUs:

Reader's command APDU Answer
Select the NDEF Tag Application 00 A4 04 00 07 D2 76 00 00 85 01 01 00 90 00
Select the Capability Container (CC) file 00 A4 00 0C 02 E1 03 90 00
Read the CC 00 B0 00 00 0F 00 0F 20 00 3B 00 34 04 06 E1 04 00 FF 00 FF 90 00
Select the NDEF file 00 A4 00 0C 02 E1 04 90 00
Read the NDEF length (NLEN) 00 B0 00 00 02 the 2-byte length + 90 00
Read the NDEF message 00 B0 <offset> <length> that part of the message + 90 00
anything else 6A 82 (not found)

Register AID D2760000850101, android:category="other" and requireDeviceUnlock="false" in res/xml/apduservice.xml. In the CC, E1 04 is the NDEF file's id, 00 FF its maximum size, the last 00 the read access (open) and FF the write access (none). The NDEF file is the 2-byte NLEN followed by the NDEF message above. Keep the Android phone on and unlocked and hold its back to the top of the iPhone.

Tip

Some Android phones run HCE only with the screen on, and some not while it clashes with Google Wallet's «default payment» choice — turn Wallet's NFC payments off for the test.

The terminal's public information

The page a phone without Gerege App opens after a tap, and Gerege App's payment sheet, show this registry information — no sign-in, no personal data:

curl -s https://geregeapp.mn/api/v1/miniapp/pay/t/7k2m9x4q3p
{"object": "terminal",
 "merchant": {"name": "Vending.mn", "icon_url": "https://…"},
 "terminal": {"code": "7k2m9x4q3p", "label": "Машин №7", "location": "СБД, 1-р хороо"},
 "pending": {"object": "payment", "merchant": {"name": "Vending.mn", "icon_url": "https://…"},
             "terminal": {"code": "7k2m9x4q3p", "label": "Машин №7", "location": "СБД, 1-р хороо"},
             "amount": 3500, "currency": "MNT", "status": "requires_confirmation",
             "claimed": false, "expires_at": "…", "livemode": true}}

pending is the open, unclaimed live basket, or null. 404 — an unknown or disabled terminal, or a suspended merchant. 120 requests a minute.

Sticker security

  • A sticker holds no secret — it only names the terminal. The amount comes from the intent your server created.
  • The risk of a fake sticker pasted over yours: Gerege App's payment sheet shows the registered name (label), location (location) and the merchant's approved name before Face ID — so name machines clearly in the registry («Машин №7», «СБД, 1-р хороо»). Inspect your machines regularly for stickers on top of stickers and lifted edges.
  • Remote claims: the code is printed, so anyone can claim — an unconfirmed claim lapses in 90 seconds, one person can hold at most 3 unconfirmed claims at a time, and you release one with POST /payment-intents/{id}/unclaim.
  • Lock every tag. Support for NTAG 424 DNA (SUN), which gives a freshly signed URL on every read, is coming soon.