Skip to main content

Attest

POST /pos/attest

After the device is claimed, the POS proves its identity by providing HMAC signature headers. On success, it receives a short-lived attestation token used to access the keys, config, and activation endpoints. This is the fifth step in the POS activation flow.

Purpose

  • Verify the device's identity using a cryptographic signature (X-Key-Id + X-Signature)
  • Confirm the device has a valid identity key registered in the system
  • Issue a short-lived attestation token (valid for 5 minutes) cached in Redis
  • The attestation token is required for the next three steps (keys, config, activate)

Authentication

POS Activation Auth + Signature — device identification headers plus HMAC signature headers for cryptographic identity proof.

Device Identification Headers

HeaderRequiredFormatDescription
X-Device-IdYesPOS-{8_HEX_CHARS}Unique identifier for the physical POS device. Must match a pre-provisioned device. Example: POS-8F3A2C91
User-AgentYesViopay-POS/{version} ({OS}; {model})POS app version string. Must start with Viopay-POS/. Example: Viopay-POS/1.4.2 (Android 12; PAX-A920)
X-Client-TypeYesposClient type identifier. Always pos for POS devices.

Signature Headers

HeaderRequiredFormatDescription
X-Key-IdYesFree-form stringIdentifier 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 this device. Example: device-id-key-2025-01
X-TimestampYesRFC3339Current time in UTC. Must be within 5 minutes of server time (past) and no more than 1 minute in the future. Used to prevent replay attacks. Example: 2025-12-13T14:25:30Z
X-NonceYesAlphanumeric stringA unique random value generated fresh for every request. Combined with the timestamp, this prevents replay attacks. Should be at least 12 characters. Example: a1b2c3d4e5f6
X-SignatureYesv1={base64_hmac}HMAC-SHA256 signature. Compute by signing the concatenation of device_id, key_id, timestamp, and nonce (joined with \n) using the device's HMAC secret. Base64-encode the result and prefix with v1=. Example: v1=SGVsbG8gV29ybGQ=

See the Headers Reference for complete details on all POS headers.

Request

No request body is required. Authentication is entirely header-based.

Response

200 OK

{
"status": "attested",
"attestation_token": "att_f83kLmP9s2ab",
"expires_in_sec": 300
}
FieldTypeDescription
statusstringAlways "attested" on success
attestation_tokenstringToken to use for keys, config, and activation (prefix: att_)
expires_in_secintegerSeconds until the token expires (always 300)
Token Lifetime

The attestation token expires in 5 minutes. You must complete the keys, config, and activation steps within this window. If it expires, call /pos/attest again to get a new token.

400 Bad Request

{
"error": {
"code": "4000",
"message": "Missing required headers",
"details": {
"required_headers": ["X-Device-Id", "X-Key-Id", "X-Timestamp", "X-Nonce", "X-Signature"]
},
"trace_id": "abc123..."
}
}

404 Not Found — Device or Key Not Found

{
"error": {
"code": "4004",
"message": "Key ID not found or not active for this device",
"details": {
"key_id": "device-id-key-2025-01",
"device_id": "POS-8F3A2C91"
},
"trace_id": "abc123..."
}
}

Code Examples

curl -X POST https://api.viopay.io/pos/attest \
-H "X-Device-Id: POS-8F3A2C91" \
-H "X-Key-Id: device-id-key-2025-01" \
-H "X-Timestamp: 2025-12-13T14:25:30Z" \
-H "X-Nonce: a1b2c3d4e5f6" \
-H "X-Signature: v1=SGVsbG8gV29ybGQ=" \
-H "User-Agent: Viopay-POS/1.4.2 (Android 12; PAX-A920)" \
-H "X-Client-Type: pos" \
-H "Content-Type: application/json"

What's Next?

Use the attestation token to download encryption keys:

Next step → Get Keys