Overview
The POS device goes through a multi-step activation flow before it can process payments. Each step must be completed in order.
See End-to-End Example for sample requests, MSK envelopes, and a charge after activation.
Flow Diagram
┌──────────────────────────────────────────────────────────────────────┐
│ POS DEVICE ACTIVATION FLOW │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ 1. Bootstrap│────▶│ 2. Pairing │────▶│ 3. Status │ │
│ │ (POS) │ │ Code (POS)│ │ (POS) │ │
│ └─────────────┘ └──────────────┘ └──────┬──────┘ │
│ │ │
│ ┌─────────────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────┐ │
│ │ 4. Claim Device (Web/Portal) │ │
│ │ (Merchant enters pairing │ │
│ │ code in backoffice UI) │ │
│ └──────────────┬───────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 5. Attest │────▶│ 6. Keys │────▶│ 7. Config │ │
│ │ (POS) │ │ (POS) │ │ (POS) │ │
│ └─────────────┘ └─────────────┘ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ 7b. Terminal│ │
│ │ Parameters │ │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ 8. Activate │ │
│ │ (POS) │ │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ 9. Charge │ │
│ │ (HMAC+MSK) │ │
│ └─────────────┘ │
│ ✅ Payment processing │
└──────────────────────────────────────────────────────────────────────┘
Steps Explained
| Step | Endpoint | Called By | Auth | Purpose |
|---|---|---|---|---|
| 1 | POST /pos/bootstrap | POS Device | POS Activation | Connectivity check, get server time and min supported version |
| 2 | POST /pos/pairing-code | POS Device | POS Activation | Generate a 6-char pairing code (valid for 5 min) |
| 3 | GET /pos/status | POS Device | POS Activation | Poll to check if the device has been claimed |
| 4 | POST /pos/claim | Web Portal | Bearer Token | Merchant enters pairing code in backoffice to claim the device |
| 5 | POST /pos/attest | POS Device | POS Activation + HMAC | Prove device identity, receive an attestation token (valid 5 min) |
| 6 | POST /pos/keys | POS Device | Attestation Token | Download encryption keys (TMK, KEK, MSK, TPK, TDK, MAC) |
| 7a | POST /pos/config | POS Device | Attestation Token | Download MSK-encrypted core config (EMV, security, branding, merchant tip/tax/surcharge JSON) |
| 7b | POST /pos/terminal-parameters | POS Device | Attestation Token | Download MSK-encrypted legacy terminal_parameters (gzip inside envelope; chunked when large) |
| 8 | POST /pos/activate | POS Device | Attestation Token | MSK-encrypted activation (request + response) |
| 9 | POST /pos/charge | POS Device | HMAC + MSK | MSK-encrypted charge (request + response) — see POS Charges |
Key hierarchy delivered at step 6: TMK → KEK → MSK + TPK / TDK / MAC. MSK encrypts core config, activate, and charge API payloads. See Keys and End-to-End Example.
Device Status Lifecycle
inactive ──▶ claimed ──▶ activated
│ │
│ (pairing code used) │ (POST /pos/activate)
│ ▼
│ Ready to process
│ POS charges
Headers Reference
The POS APIs use three different authentication levels, each requiring different headers. This section explains every header in detail.
POS Activation Headers
Used by: Bootstrap, Pairing Code, Status, Attest
X-Device-Id
Unique identifier for the physical POS device. Assigned when the device is pre-provisioned by a merchant or reseller.
- Required: Yes
- Format:
POS-followed by an 8-character hex string - Example:
POS-8F3A2C91
User-Agent
Identifies the POS application version, OS, and hardware model. Must start with Viopay-POS/ followed by a semver version. The parenthetical section contains the OS version and device model.
- Required: Yes
- Format:
Viopay-POS/{version} ({OS}; {model}) - Example:
Viopay-POS/1.4.2 (Android 12; PAX-A920)
X-Client-Type
Identifies the type of client making the request. For POS devices, this is always pos.
- Required: Yes
- Format:
pos - Example:
pos
Attestation Signature Headers
Used by: Attest — in addition to the activation headers above.
X-Key-Id
Identifier of the device identity key used to generate the signature. This key must be registered and active (not revoked) in the merchant_device_identity_keys table for the device.
- Required: Yes
- Format: Free-form string
- Example:
device-id-key-2025-01
X-Timestamp
Current time in RFC3339 / ISO 8601 format. Used to prevent replay attacks.
- Required: Yes
- Format: RFC3339 UTC timestamp
- Validation: Must be within 5 minutes of the server time (past). Future timestamps are tolerated up to 1 minute.
- Example:
2025-12-13T14:25:30Z
X-Nonce
A unique random value generated fresh for every request. Combined with the timestamp, prevents replay attacks.
- Required: Yes
- Format: Alphanumeric string (at least 12 characters recommended)
- Example:
a1b2c3d4e5f6
X-Signature
HMAC-SHA256 signature of the request. Prefixed with v1= to allow future signature versions.
- Required: Yes
- Format:
v1={base64_encoded_hmac} - Example:
v1=SGVsbG8gV29ybGQ= - How to compute: Sign the concatenation of
device_id,key_id,timestamp, andnonce(joined with\n) using the device's HMAC secret. Then Base64-encode the result.
Attestation Token Headers
Used by: Keys, Config, Terminal Parameters, Activate
Authorization
The attestation token received from POST /pos/attest. Uses the Attestation scheme — not Bearer.
- Required: Yes
- Format:
Attestation {token} - Token prefix:
att_ - Lifetime: Valid for 5 minutes. Cached in Redis and tied to a specific device ID.
- Example:
Attestation att_f83kLmP9s2ab
X-Device-Id
Same device ID that was used during attestation. The server verifies that this matches the device ID bound to the attestation token.
- Required: Yes
- Format:
POS-{8_HEX_CHARS} - Example:
POS-8F3A2C91
HMAC Charge Headers
Used by: POST /pos/charge, POST /pos/charge/:chargeID/refund, POST /pos/charge/:chargeID/cancel — all use MSK-encrypted request/response bodies where applicable (see Create POS Charge).
X-Terminal-Id
The terminal key assigned to the device after activation. This is different from the device ID — it's the logical terminal identifier used for payment processing. Found in the config response as terminal.terminal_id.
- Required: Yes
- Format: Free-form string
- Example:
TID-004812
X-Timestamp
Current time in RFC3339 format. Same rules as attestation.
- Required: Yes
- Format: RFC3339 UTC timestamp
- Validation: Within 5 minutes past, 1 minute future.
- Example:
2025-12-13T14:25:30Z
X-Nonce
Unique random value per request.
- Required: Yes
- Format: Alphanumeric string
- Example:
f9e8d7c6b5a4
X-Key-Id
Identifier of the HMAC key used to sign the request. This is the MAC key from the key set downloaded during activation.
- Required: Yes
- Format: Free-form string
- Example:
hmac-key-2025-01
X-Signature
HMAC-SHA256 signature of the full request, Base64-encoded and prefixed with v1=.
- Required: Yes
- Format:
v1={base64_encoded_hmac} - Example:
v1=dGVzdCBzaWduYXR1cmU= - How to compute: Build the signature string by joining these values with newlines (
\n):
METHOD
PATH
QUERY
BODY
TERMINAL_ID
TIMESTAMP
NONCE
Then compute HMAC-SHA256(signature_string, hmac_secret) and Base64-encode the result.
X-Client-Type
Client type identifier. Always pos for POS devices.
- Required: Yes
- Format:
pos
User-Agent
POS application identifier. Same format as activation headers.
- Required: Yes
- Format:
Viopay-POS/{version} ({OS}; {model}) - Example:
Viopay-POS/1.4.2 (Android 12; PAX-A920)
Idempotency-Key
Unique key to ensure the charge is only processed once. If a charge with the same idempotency key already exists, the existing response is returned instead of creating a duplicate.
- Required: No (optional)
- Format: UUID or free-form string
- Example:
550e8400-e29b-41d4-a716-446655440000
Bearer Token Header
Used by: Claim Device — called from the web portal, not the POS device.
Authorization
Keycloak JWT access token. Obtained via user login or POST /client/session (API client credentials). A session must be initiated via /session/initiate before making merchant-scoped requests.
- Required: Yes
- Format:
Bearer {jwt_token} - Example:
Bearer eyJhbGciOiJSUzI1NiIs...
What Happens After Activation?
Once the device is activated, it uses HMAC signature authentication to process payments:
POST /pos/charge— Create a payment (MSK encrypt request + decrypt response)POST /pos/charge/:chargeID/refund— Refund a payment (MSK encrypt request + decrypt response)POST /pos/charge/:chargeID/cancel— Cancel a payment (MSK decrypt response)POST /pos/charge/:chargeID/reverse— Reverse a payment (same as cancel)