Terminals and the POS app
How ZyloPay terminals read wallet passes, how they relate to the API, and how to provision and run them.
A terminal is an Android POS device running the ZyloPay POS app. It is where the customer taps. Your servers never touch the customer's pass: the terminal reads it and talks to ZyloPay directly.
flowchart LR
subgraph Store
P[Customer wallet pass] -- NFC tap --> T[ZyloPay POS app]
end
T -- device key --> Z[ZyloPay]
S[Your servers] -- API key --> Z
Z -- webhooks --> S
Z -- settlement --> M[(Monad)]
Devices
| Device | Notes |
|---|---|
| Multzo H10 and other Android NFC terminals | Generic build of the POS app. |
| Clover Flex, Mini and Station | Clover build, with Clover Register integration and the customer-facing display on Station Duo. |
The POS app handles tips, tax, discounts, split payments across several customers, digital receipts by email or SMS, refunds, shift reports and employee roles with PIN login.
How the tap works
Customers add a ZyloPay pass to Apple Wallet or Google Wallet from the ZyloPay payer app. At the terminal:
- Google Wallet passes are read with Google Smart Tap.
- Apple Wallet passes are read with Apple VAS (Value Added Services).
- If NFC is not available, the terminal can scan the pass's QR code, which carries a short-lived payment token.
The pass holds a credential for that one pass, never the customer's signature or keys. The terminal sends it to ZyloPay over TLS with its device key. ZyloPay resolves it to the pass and the customer's spending approval, runs its checks and settles.
Smart Tap needs a collector key that ZyloPay hands to the terminal after provisioning. On mainnet it needs an approved business verification. On testnet, when no testnet collector is configured, terminals take QR payments only.
Provisioning
Terminals are created in the dashboard, Settings → POS Terminals → Add Terminal, by owners and admins.
- Choose the mode first (Sandbox or mainnet). A terminal belongs to one network for its whole life.
- The dashboard shows the terminal's device key once, with a QR code and a setup link. Scan it from the POS app's setup screen.
- The terminal appears in
GET /v1/terminalswith its ID (tml_…) and label, andterminal.createdis sent.
The device key is a secret. It authenticates the terminal only, for your merchant, on its network. It is not an API key and must never be used from your servers.
Deactivate a lost or retired terminal in the dashboard. Its key stops working at once and terminal.deactivated is sent. A deactivated terminal can then be deleted (terminal.deleted); its payments stay in your history.
Terminals and the API
| You want to | Use |
|---|---|
| List terminals, see which are active and when they were last seen | GET /v1/terminals (last_seen_at) |
| Send a payment to a terminal from your system | POST /v1/payment_intents with terminal |
| Know about every sale on every terminal | payment.succeeded webhooks, GET /v1/payments?terminal=tml_… |
| Refund a sale taken on a terminal | POST /v1/refunds (the POS app can also refund) |
Payment intents from the API. A terminal collects intents created for it by polling ZyloPay with its device key, oldest first, and settles them through the same path as a cashier-started payment. The ZyloPay POS app picks up intents from the release that adds intent pickup, which is rolling out now: confirm with support that your terminals run it (a terminal without it leaves intents unpaid until they expire). Terminal-started payments work on every release and reach you as payment_intent.* events with source: "terminal" and payment.succeeded.
The terminal protocol (device-key endpoints) is not part of the public API. If you plan to build your own terminal software, contact ZyloPay.
Safety built into the terminal
- No blind retries. A payment that was sent but whose outcome is unknown is never re-sent. The terminal shows "Check status", which asks ZyloPay for the final outcome.
- Offline queue. Only requests that provably never left the device are queued and sent when the connection returns.
- Payer confirmation. When a payment is held for the customer's confirmation, the terminal waits and shows the result. The cashier can cancel the request.
- Daily cap. Each terminal has a daily volume cap. A payment beyond it is declined with
terminal_daily_limit. - Disabled or unverified account. A terminal of a disabled account, or a mainnet terminal without an approved business verification, blocks sales with a full-screen message.
Getting the POS app
Ask your ZyloPay contact for the POS app build for your devices and for installation support.