Payment in the app is the checkout screen: one order, one or more tenders, a receipt. Card-present payment runs through Stripe Terminal; everything else is a recorded tender. This page is what to configure and what to expect.
Gateways
GET /storefront/payment-gateways tells the app which gateways the organization has: Stripe, PayPal or Helcim, each with its public key. Card payment in the app is Stripe only. PayPal and Helcim appear in the list but the mobile checkout does not drive them; a sale on those is recorded as an "other" tender with a reference.
/storefront/payment-gatewaysNo auth/storefront/stripe/intentNo auth/storefront/stripe/terminal/connection-tokenNo auth/storefront/stripe/terminal/location/ensureNo auth/storefront/stripe/terminal/intentNo authStripe Terminal
Card-present uses the Stripe Terminal SDK. The app supports external readers (Stripe M2, BBPOS WisePOS, WisePad) over Bluetooth, and Tap to Pay on the phone's own NFC where the device qualifies.
Locations
Every reader registers against a Stripe Terminal location. Pairing cannot start without one. The app lists existing locations and can create one for the selected business location (.../terminal/location/ensure); the choice is saved on the device as stripe_terminal_location_id.
Pairing a reader
More → Payments runs a wizard; each step gates the next.
1. Venue. Which venue is this reader for? — the organization's business locations. With none, the wizard stops at No business locations on this org yet.
2. Address. A venue with no address is asked for street, state or region and a two-letter country code. Stripe requires it to register the Terminal location, which the app then does for you.
3. Prepare the reader. On an M2, hold the power button for about four seconds until it flashes.
4. Scan. The app fetches a connection token from the server and lists nearby readers by serial. Rescan if yours is not there.
5. Pair. Connecting can take up to 30 seconds. On a first pair the reader then takes a firmware update — the screen says Updating reader firmware and warns it can take 2 to 5 minutes. Keep it powered and in range; interrupting this is the usual cause of a reader that never pairs cleanly afterwards.
6. Done. The reader's serial is saved (stripe_terminal_reader_serial) and reconnects automatically next session. Unpair and Pair a different reader are on the same screen.
Connection tokens rotate on their own through the SDK; there is nothing to renew.
Tap to Pay
Tap to Pay is not configured in the wizard. It is initialized when checkout first needs it, on devices that support it:
| Platform | Requirement |
|---|---|
| iPhone | XS or later, iOS 16.4 or later |
| Android | NFC and Android 11 or later |
| iPad | Not supported by Stripe |
The app probes support once per session and hides the option where it is unavailable.
The charge
A terminal payment creates a card_present intent on the server, then the SDK collects the card on the reader and confirms. The intent id is stored as the tender's reference when the tab settles, so a payment can be traced from the order to Stripe.
The reader talks to Stripe through the app. Nothing is queued; a payment attempted without connectivity fails and can be retried. Cash and other tenders record without a network round trip only in the sense that the settle call still has to reach the server.
The tender model
At checkout a tab is settled with one or more tenders:
| Method | Notes |
|---|---|
cash | Carries the amount tendered; the app shows change due. The only method allowed to exceed the amount owed. |
card | A card charged outside the app — recorded with a reference. |
terminal | Reader or Tap to Pay through Stripe Terminal. |
bank | Transfer, recorded with a reference. |
other | Anything else, with a note. |
Rules the server applies on POST /storefront/pos/tab/:id/settle:
- The order is re-priced first; the amount owed is what the server computes, not what the screen last showed.
- A tab already fully paid is refused, as is a zero or negative amount.
- Overpayment is accepted only for cash (change is recorded). Any other tender over the amount due is refused.
- Each tender is charged independently. Adding a tip rebalances the first uncharged tender; charged rows are locked.
- The transaction is keyed on the human order number and posted to the ledger.
Refunds
Refunds are per recorded payment on a tab: POST /storefront/pos/tab/:id/refund with the transaction id or reference, and an optional partial amount. The refunded line is dimmed in the tab's payment list. A terminal payment refunds through Stripe; a cash refund is a ledger entry and the drawer is on you.
Receipts
Once the total is covered, checkout offers print, email, SMS or none. Email and SMS go through POST /storefront/pos/tab/:id/send-receipt for any tender, not only card payments, using the pos-receipt templates. Printing uses the paired printer.
What is not there
- Payment links. There is no send-a-link flow in the app. A phone order is taken as a card or other tender with a reference, or invoiced from Studio Manager.
- Saved cards / customer wallets. Not on mobile.
- PayPal and Helcim checkout. Listed as gateways; not driven from the mobile checkout.
When something goes wrong
| Symptom | Cause | Fix |
|---|---|---|
| No business locations on this org yet | The wizard has no venue to register against | Create a business location on the web, then restart the wizard. |
| Save failed: … on the address step | Stripe rejected the address, or the write failed | Check the country is a two-letter code and the state matches the country. |
| Discovery failed: … | Bluetooth off, or the reader is not in pairing mode | Turn Bluetooth on; hold the M2 power button ~4 seconds and rescan. |
| Pairing sits for minutes on a first pair | Firmware update, 2–5 minutes | Wait it out, powered and in range. Do not close the screen. |
| No M2 reader paired. Pair one in Devices first. at checkout | No reader saved on this device | Pair now, or use another tender. |
| The reader worked yesterday, not today | It was paired to another device, or someone signed out here | Re-pair. Sign-out clears the saved serial and Terminal location. |
| Tap to Pay is not offered | The device does not qualify | iPhone XS+/iOS 16.4+, or Android 11+ with NFC. Never on iPad. |
| Stripe is not configured. Add a StripeProvider integration. | The organization has no Stripe gateway | Configure it in Studio Manager; nothing on the device fixes this. |
| Failed to create Stripe payment intent. | The intent could not be opened | Retry once, then check connectivity and the gateway's keys. |
| Card declined | The bank refused | Another card, or another tender. Nothing was taken. |
| A settle "failed" but may have gone through | The response was lost, not the payment | Open the tab's payment list before charging again; refund a duplicate rather than voiding the tab. |
| An overpayment is refused | Only cash may exceed the amount due | Take the exact amount on card, or settle the remainder in cash. |
| A tab refuses to settle | It is already fully paid | Check the payment list; it may have settled on another device. |