Configuration Endpoints
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.
These endpoints carry admin settings to the register. The device reads the global config and the unified per-terminal payload. Configuration flows one way: no route lets a terminal write location settings back to Magento.
| Method | Route | ACL | Purpose |
|---|---|---|---|
GET |
/V1/pos/config |
Hyva_Pos::locations |
Global POS configuration, defaults, enforcement flags |
GET |
/V1/pos/terminals/:terminalId/config |
Hyva_Pos::locations |
Unified per-terminal bootstrap payload |
GET |
/V1/pos/postcode-patterns |
Hyva_Pos::locations |
Per-country postcode validation patterns |
GET |
/V1/pos/order-statuses |
Hyva_Pos::locations |
Registered order statuses for picker UIs |
Global Config (GET /V1/pos/config)
Returns everything under Stores > Configuration > Hyvä POS as one object, plus feature-availability flags derived from the installed modules and provider pools. Called by the device on every settings sync, including before a PRO module is detected; it is how the app discovers what the store supports.
The response body is a JSON-encoded string (the object serialized twice). Parse the body, then parse the resulting string. Abridged example after decoding:
{
"module_version": "1.3.0",
"enabled": true,
"require_staff_login": true,
"share_held_carts": true,
"require_terminal_registration": true,
"default_order_status": "",
"default_payment_methods": "cash,card",
"default_allow_store_credit": 1,
"default_low_stock_threshold": 10,
"default_use_msi": true,
"default_receipt_header": "Thank you for shopping with us",
"default_receipt_footer": "",
"default_receipt_show_staff_name": true,
"default_receipt_show_order_number": true,
"default_layaway_deposit_min_percent": 25,
"default_layaway_expiry_days": 30,
"default_layaway_cancellation_fee_percent": 0,
"default_pickup_queue_filter": "all",
"card_payments": {
"provider": "mollie",
"mollie": {
"enabled": true,
"organisation_id": "org_12345",
"api_key": "live_...",
"test_api_key": "test_...",
"test_mode": false
},
"providers": {
"paynl": {
"enabled": false,
"token_code": "AT-1234-4321",
"api_token": "...",
"service_id": "SL-1234-4321",
"test_mode": false,
"service_secret": "..."
}
}
},
"walk_in_customer": {
"first_name": "POS",
"last_name": "Customer",
"email": "store@example.com",
"phone": "+31 20 123 4567",
"street": "Main Street 1",
"city": "Amsterdam",
"region_id": 0,
"postcode": "1234AB",
"country_id": "NL"
},
"telemetry": { "enabled": false, "force_enabled": false, "upload_hour": 3 },
"tax": {
"price_includes_tax": true,
"apply_after_discount": true,
"discount_tax": true,
"display_type": 2,
"cart_display_price": 2,
"cart_display_subtotal": 2,
"sales_display_zero_tax": false,
"cart_display_zero_tax": false,
"calculation_algorithm": "TOTAL_BASE_CALCULATION",
"reverse_charge_enabled": false,
"tax_exempt_enabled": false,
"weee": {
"enabled": true,
"apply_vat": false,
"include_in_subtotal": false,
"display_sales": 1,
"display_product": 1,
"display_list": 1,
"attributes": [{ "code": "recycling_fee", "label": "Recycling fee" }]
}
},
"enforcement": { "receipt_header": "1", "payment_methods": "0", "tax_settings": "1" },
"payments": {
"pay_by_invoice_method": "checkmo",
"pay_by_invoice_invoicing_mode": "open",
"credit_limits_enabled": true,
"providers": { "mollie": { "magento_method": "mollie_methods_pointofsale" } },
"available_terminal_payment_methods": [
{ "code": "checkmo", "label": "Check / Money order" },
{ "code": "mollie_methods_pointofsale", "label": "Point of sale" }
],
"builtin_refunds_enabled": true
},
"credits": {
"store_credit_includes_tax": false,
"reward_points_includes_tax": false,
"gift_card_includes_tax": false,
"refund_to_store_credit": false
},
"license": { "connected": true },
"has_credit_providers": true,
"has_rma_providers": true,
"has_wishlist": true,
"has_customer_balance": false,
"has_gift_card": false,
"has_reward_points": false,
"has_rma_module": false,
"has_msi": true,
"shipping_label_providers": [],
"credit_providers": [
{ "key": "store_credit", "code": "pos_builtin", "enabled": true, "label": "Store Credit" }
],
"rma_providers": [
{ "key": "rma", "code": "pos_builtin", "enabled": true, "label": "Built-in Returns" }
]
}
The default_* keys are website- or store-scope fallbacks; a location row without an explicit value inherits them.
has_msi says whether the store has Magento Inventory (Magento_InventoryApi enabled); without it the register skips the /V1/inventory/* routes. default_use_msi is the Use Multi-Source Inventory default (hyva_pos_terminal/stock/use_msi, on by default), which a location's use_msi overrides; it is false whatever the setting says when has_msi is false.
credits.refund_to_store_credit (module 1.3.0) says whether the store refunds to store credit by default, as the active store-credit provider answers it (MemoCreditIssuerInterface::refundsToStoreCreditByDefault()). It is false without a provider, for a provider that books no refund to store credit, and when the read fails. The register preselects the Store Credit channel in its refund dialog from it.
sales_display_zero_tax and cart_display_zero_tax are Magento's Display Zero Tax Subtotal switches for sales documents and for the cart (module 1.2.0 and later). With the sales switch on, a receipt whose tax comes to zero still prints its VAT rows at 0.00; with the cart switch on, the customer display does the same. Both default to off, as in Magento.
tax.weee relays Magento's Fixed Product Tax settings (Stores > Configuration > Sales > Tax > Fixed Product Taxes) so the register charges recycling and disposal fees the way the storefront does. The fee amounts travel on the product, in the custom_attributes rows of the FPT attribute on GET /V1/products/{sku} (the product list does not include them, so the register reads them per product); this block says whether the store charges them, whether they are taxed, whether they count towards the subtotal, and what each one is called. enabled is off when the setting is off or Magento_Weee is disabled, in which case attributes is empty. The three display keys carry Magento's own values: 0 including FPT, 1 including FPT and its description, 2 excluding FPT but showing the description and the final price, 3 excluding FPT; display_sales covers the cart and order surfaces, display_product the product view, display_list product lists, and Magento's default is 1. Every value is read at store scope, and none of them is lockable or overridable per location: they describe the store's tax setup, not the terminal's. The card_payments.mollie block contains decrypted API keys for the device, so scope integration tokens accordingly.
Customer Validators Are Server-Side Only
hyva_pos_terminal/customers/validators (website scope, Stores > Configuration > Hyvä POS > Terminal Defaults > Customers) selects which customer validators run on POST /V1/pos/customer-validate and POST /V1/pos/customers. It is applied by Hyva\Pos\Model\Customer\CustomerValidatorPool and is deliberately absent from this payload: the device sends a draft customer and reads back error rows, it does not decide which checks produce them.
The stored value is the comma-separated list of pool registration keys the multiselect saved. required_fields and email_uniqueness always run and are not offered as options. An empty value, which is the default, runs every registered validator, so a validator bridge keeps working on a store that never opens the setting. A selected key that is no longer registered is ignored, and registration order (di.xml) decides execution order, not the order the options were ticked. The pool reads the setting against the website_id on the validation request, falling back to the default scope when that is 0.
Unified Terminal Config (GET /V1/pos/terminals/:terminalId/config)
The bootstrap payload the device pulls at activation, at launch, and whenever the heartbeat's config_hash changes. One call replaces separate fetches of config, location, staff, and roles. Also a JSON-encoded string; parse twice. Envelope keys:
| Key | Content |
|---|---|
terminal |
The terminal row, with license fields injected: license_id, license_token, license_status, license_type, license_expires_at, fiskaly_tss_id, fiskaly_api_key |
license |
The full linked license record, or null |
config |
The same object as GET /V1/pos/config |
location |
The terminal's location row, with the address already resolved (when address_use_storeview is on, store-view values are swapped in server-side) |
resolved_config |
The effective flat config: terminal overrides layered over location values over global defaults. Read this instead of re-implementing precedence |
staff |
Active staff assigned to the location (or with all_locations). The bcrypt passcode hash is stripped; passcode_updated_at is included |
roles |
The roles referenced by those staff rows |
Errors: 404 with Terminal with id "%1" does not exist. for an unknown terminal id. A deleted location yields "location": null rather than an error.
Enforcement Flags and How Locks Work
Each flag lives at hyva_pos_lock/enforcement/<field> (website scope, Stores > Configuration > Hyvä POS > Lock Settings) and is delivered in the enforcement block as string "1" (enforced: the device renders the setting read-only and shows it as managed) or "0" (the device may customize it per location). Defaults are "0".
| Flag | Locks |
|---|---|
receipt_header / receipt_footer |
Receipt header and footer text |
receipt_show_staff_name / receipt_show_order_number |
Cashier-name and order-number visibility on receipts |
receipt_show_receipt_number / receipt_show_sale_reference |
Receipt-number and sale-reference visibility on receipts |
receipt_qr |
Receipt-bottom QR text and URL |
auto_print |
What prints on checkout success: the customer receipt and the customer and merchant terminal slips |
payment_methods |
The set of available payment methods |
card_payment_provider |
The card payment Mode: Manual or a terminal provider |
allow_store_credit |
Whether store credit is offered in the Discounts panel |
mollie_magento_method |
Which Magento payment method backs Mollie-routed card sales (per-location overrides ignored) |
mollie_config |
Mollie terminal settings (keys, organisation id, test mode) |
paynl_config |
PAY. terminal settings (token code, API token, sales location, its secret, test mode) |
paynl_magento_method |
The Magento payment method PAY. terminal sales book under; with the lock on, a location's override is ignored |
pay_by_invoice_method / pay_by_invoice_invoicing_mode |
Pay-by-invoice payment method and invoice behavior |
refund_validity |
The online-refund validity window |
cash_rounding_increment |
The cash rounding step |
require_open_session |
Whether a register session must be open before a tender is offered |
store_details |
Store address, phone, and VAT number |
tax_settings |
Tax calculation and display settings |
low_stock_threshold |
The low-stock warning threshold |
use_msi |
Whether registers read and write stock per source through Magento Inventory |
held_carts |
The "Share Held Carts" toggle |
custom_sale_sku |
The SKU free-entry register lines are booked against |
categories |
Which top-level categories appear on the register landing page |
walk_in_customer |
Walk-in customer default name / email / phone / address |
pickup_queue_filter |
The default pickup-queue filter |
customer_prices |
When customer prices are fetched |
promo_attribute_lookup |
Whether missing promotion attributes are fetched from Magento |
Postcode Patterns (GET /V1/pos/postcode-patterns)
Relays Magento's etc/postcodes.xml so the device can validate addresses client-side without a parallel hardcoded list. Returns a JSON-encoded string keyed by ISO 3166-1 alpha-2 country code; each country maps to an array of {pattern, example} rows, and any matching row is a pass (the US, for example, has both 5-digit and ZIP+4 rows):
{
"NL": [{ "pattern": "^[0-9]{4} ?[a-zA-Z]{2}$", "example": "1234AB" }],
"US": [
{ "pattern": "^[0-9]{5}$", "example": "12345" },
{ "pattern": "^[0-9]{5}-[0-9]{4}$", "example": "12345-6789" }
]
}
Order Statuses (GET /V1/pos/order-statuses)
Every registered row from sales_order_status, including custom merchant statuses. Feeds the location-config "post-pickup status" dropdown (pickup_completed_status_code).