Skip to content

Terminal Payments

Hyvä POS is in closed beta

Hyvä POS is currently in a closed beta (pilot phase) with a small group of merchants. It is not yet generally available: the App Store release follows the pilot, and features and configuration may still change, possibly in backwards-incompatible ways, before the general release. Want to take part? Sign up at hyva.io/pos.

An integrated terminal means the app drives the card machine: the amount appears on the terminal on its own, the customer taps or inserts, and the sale completes when the payment confirms. The amount is not typed twice, so a typo on the terminal cannot charge the wrong amount.

How Provider Integrations Work

Terminal integrations are built into the native app: each payment provider's terminal protocol is implemented and tested by Hyvä, in partnership with that provider. It is not a plug-in system where any PSP can be added by a third party.

  • Mollie: sales and refunds, on the free tier and PRO.
  • PAY.: sales through PAY. terminals and PAY.POS phones over Cloud Connect, and refunds to the card that paid, on the free tier and PRO.
  • Adyen and Stripe: in development, release date unknown.

The Flow at the Register

  1. The cashier picks Card at checkout. The payment panel shows the paired terminal by name; a counter with several terminals configured switches per payment from the same panel.
  2. The cashier taps pay. The app creates a payment with the provider and the amount appears on the terminal; for a split sale, only the card portion. A connected customer display shows "Please pay" with the amount.
  3. The customer taps or inserts. The app polls the payment every two seconds while an overlay shows the waiting state.
  4. On confirmation the overlay closes and the app places the Magento order, recording the provider's payment id and the card metadata with the sale. The payment happens first; the order is placed only for a collected payment.

There is no tip prompt in the flow: Hyvä POS does not offer tipping.

What the Cashier Sees While Waiting

The overlay tracks the payment from the register side:

  • Waiting: the terminal's name and the amount, with Cancel always available. Where the provider accepts a cancel, the register cancels the payment there, so the customer cannot complete a payment the cashier has abandoned. A payment the provider will not cancel, such as a Mollie point-of-sale payment, is never sent a cancel. The overlay then says "This payment cannot be stopped from the register. Cancel it on , or wait for it to expire." and the register keeps watching the payment for up to 15 minutes. Stop watching leaves the payment open at the provider and lists it under Reports → Terminal Payments.
  • Taking too long: after a threshold the overlay suggests the terminal may be unavailable and shows the fallback actions.
  • Declined / cancelled / expired: the reason, with Retry as the primary action. The cart is untouched: retry, switch to another paired terminal from the overlay, or back out and pick a different tender.
  • Test mode: when the provider is configured with a test key, a visible test-mode badge shows on the payment panel, so a test key does not go unnoticed at checkout.

Where It's Configured

  • In the app: Settings → Payments → Card Payments. Switch the processing mode from Manual to the provider, enter the provider credentials, and pair a terminal. The provider pages walk through it.
  • In Magento (PRO): the same credentials and method mapping live at Stores → Configuration → Hyvä POS → Payments → Card Payments, under Mollie and PAY., with per-location overrides. Every register applies them as they arrive and lists the changes under Applied by Magento. A locked field shows a lock and a Magento badge on the device and cannot be edited there; an unlocked field can be edited on the device, and the edit holds until Magento's value next changes. See global settings.
  • On PRO, re-pairing to a different terminal is gated by the hardware-configuration permission (managers and up by default); taking payments through the paired terminal is not.

Failure Handling

Every provider integration handles connection problems the same way:

  • Idempotent payments: every payment carries a unique key, so a network drop during creation cannot double-charge; retrying returns the same payment. A double tap on the pay button is rejected; only one payment can be in flight.
  • Recovery over failure: on provider server errors the app retries with the same key and, if needed, matches the payment among recent transactions rather than showing a false failure.
  • A bounded wait, and the provider has the last word: the app polls the payment for up to 60 seconds. When the cashier taps Cancel, or the wait runs out, the register cancels at the provider where the provider accepts a cancel, and then asks it what became of the payment. A payment the customer completed in that moment is booked as a sale; a cancellation the provider confirms is a cancellation; anything the provider does not confirm is shown as Payment not confirmed, with a Check payment button and no retry, so the customer is never charged twice for one sale. A payment the provider will not cancel is not sent one: the register keeps reading it for up to 15 minutes, until the terminal or the payment's own expiry ends it, and a payment still open after that is listed under Reports → Terminal Payments.
  • Failure is explicit: a declined, cancelled or expired payment shows the reason on the overlay with Retry as the primary action; the cart is untouched, so the cashier retries, switches to another terminal mid-payment, or picks a different tender.
  • If the app dies mid-payment, or the answer never arrives: every attempt is written on the device before the provider is asked, with the reference the provider received. Attempts without a confirmed outcome are listed under Reports → Terminal Payments, also after a relaunch. Check reads each back through the provider that took it; a confirmed cancellation or decline removes it; money the provider confirms with no order behind it can be refunded to the card from there. An attempt the provider never answered carries no payment id to read: Enter payment id links it to the payment found in the provider's dashboard. Settled at the provider removes an attempt after the cashier has checked at the provider that it took no money, or that what it took was refunded there.
  • Manual fallback: if the terminal stays unreachable, Process manually lets the cashier, after an explicit confirmation, settle the payment as a manual card entry. The cart is kept.

What Ends Up on the Receipt and the Order

The provider returns the full card metadata on confirmation, and the app stores it with the sale:

  • On the terminal slip: card brand and masked number, cardholder where the scheme provides it, chip/contactless indicator, authorization code, acquirer reference (ARN), EMV application details, entry and verification mode, and the authorization timestamp. Customer and merchant copies have their own auto-print switches (per device, or pushed from Magento on PRO).
  • Because the metadata is stored with the sale, slips can be reprinted later, offline included, from the receipts list.
  • The Magento order books under the provider's payment method (see the provider page for the mapping) with the POS payment details in the order comments, and the sale keeps a direct link to the payment in the provider's dashboard for reconciliation.

Payment First, Order Second

The order is placed only after the provider confirms the payment. The reverse case is covered too:

  • The sale is recorded on the device the moment payment confirms, before the order call to Magento. A failure between payment and order placement does not lose the sale; it shows as pending and syncs on retry.
  • On PRO, a network drop after the payment queues the finished order; the receipt prints from the local record and the queue drains on reconnect.
  • Every sale carries a unique id, so an order-placement retry returns the existing Magento order instead of creating a duplicate. See how orders are placed.

Note that the payment itself always needs a route to the provider: terminal payments are payments over the internet, so a fully offline counter takes cash or falls back to the manual reference flow while the connection is down.

No Integrated Terminal?

The manual reference flow covers any terminal from any provider, today: type the amount into the terminal, and record the payment in the app with the terminal's reference number.

Refunds go back to the card on both tiers

A refund of a terminal-paid sale is returned to the customer's card on both tiers. The app refunds through the terminal provider directly when the sale carries a terminal payment; otherwise the credit memo it creates in Magento is an online refund, and the provider's Magento module (Mollie's, for example) returns the payment automatically. Only sales recorded with the manual reference flow have no payment to refund against; those are reversed on the standalone terminal by hand.