Config
Downloads the core device configuration: terminal info, merchant details (tip, tax, surcharge), location, EMV parameters, security settings, branding, and operational intervals. Legacy VIPAY terminal_parameters are delivered separately via Terminal Parameters because that payload is large (~200 KB).
This is step 7a in the POS activation flow (after keys, before terminal parameters and activate).
MSK encryption: The HTTP response is an MSK-encrypted envelope (TR31-DATA). Decrypt with the terminal MSK (from POST /pos/keys) using AES-256-CBC to obtain the core config JSON described below.
See End-to-End Example for the full activation walkthrough including MSK decrypt.
Purpose
- Retrieve the terminal ID and device ID mapping
- Get the merchant name, key, tip/tax/surcharge JSON (
tip_info,tax_info,surcharge_infofrom themerchantstable), and associated location details - Load EMV configuration (AID list, terminal capabilities, terminal type)
- Apply security settings (PIN requirements, contactless limits, fallback rules)
- Set branding (theme and logo URL)
- Configure operational intervals (heartbeat, update check)
Not included here: terminal_parameters (acquirer lists, CA keys, EMV kernel configs). Fetch them with POST /pos/terminal-parameters and merge locally — see Terminal Parameters.
Authentication
POS Attestation Auth — requires the attestation token received from POST /pos/attest.
| Header | Required | Format | Description |
|---|---|---|---|
Authorization | Yes | Attestation {token} | The attestation token from the attest step. Uses the Attestation scheme (not Bearer). The token starts with att_, is cached in Redis, and is valid for 5 minutes from issuance. Example: Attestation att_f83kLmP9s2ab |
X-Device-Id | Yes | POS-{8_HEX_CHARS} | The same device ID used during attestation. The server verifies that this device ID matches the one bound to the attestation token. Example: POS-8F3A2C91 |
See the Headers Reference for complete details.
Request
No request body is required.
Response structure
The decrypted config contains back-office fields only: terminal, merchant, location, security, emv, branding, and device_config. Merge terminal_parameters from the separate terminal-parameters endpoint into your local config object before activation.
Response
200 OK — MSK-encrypted envelope
The API returns ciphertext, not plain JSON. Decrypt locally with MSK to obtain the config object.
{
"format": "TR31-DATA",
"ciphertext": "A1B2C3...",
"initialization_vector": "000102030405060708090A0B0C0D0E0F",
"mode": "CBC",
"key_kcv": "ABCD12"
}
| Field | Description |
|---|---|
format | Always TR31-DATA |
ciphertext | AES-256-CBC encrypted config payload (hexBinary) |
initialization_vector | IV used for encryption (hexBinary, 16 bytes) |
mode | Encryption mode — CBC |
key_kcv | MSK key check value for verification |
Decrypted config JSON
After MSK decrypt, the plaintext is UTF-8 JSON with this structure:
{
"terminal": {
"terminal_id": "TID-004812",
"device_id": "POS-8F3A2C91"
},
"merchant": {
"merchant_key": "mk_acme_corp",
"name": "Acme Corp",
"tip_info": {
"tip_type": "percentage",
"tip_label": "Tip",
"tip_enabled": true,
"tip_description": "Show your appreciation",
"allow_custom_tip": true,
"maximum_tip_amount": 0,
"minimum_tip_amount": 0,
"suggested_tip_amounts": [1, 3, 5],
"default_tip_percentage": 18,
"suggested_tip_percentages": [15, 18, 20]
},
"tax_info": {
"tax_rate": 2.35,
"tax_number": "512512512512515125",
"tax_region": "US-AZ",
"tax_enabled": true,
"tax_inclusive": true,
"liability_accepted": true
},
"surcharge_info": {
"surcharge_type": "percentage",
"surcharge_label": "Credit card surcharge",
"surcharge_enabled": true,
"liability_accepted": true,
"surcharge_percentage": 3,
"surcharge_description": "A 2.5% processing fee applies to Visa credit card transactions. Debit cards are not subjected to this surcharge.",
"surcharge_fixed_amount": 3,
"maximum_surcharge_amount": 0,
"apply_to_credit_cards_only": true,
"minimum_transaction_amount": 0
}
},
"location": {
"name": "Main Street Store",
"timezone": "America/New_York"
},
"security": {
"pin_required": true,
"online_pin": true,
"contactless_limit_minor": 5000,
"fallback_allowed": true
},
"emv": {
"aid_list": [
"A0000000031010",
"A0000000041010",
"A00000002501"
],
"terminal_capabilities": "E0F0C8",
"additional_terminal_capabilities": "F000F0A001",
"terminal_type": "22",
"application_version_number": "0001"
},
"branding": {
"theme": "dark",
"logo": "https://cdn.viopay.io/acme/logo.png"
},
"device_config": {
"heartbeat_interval_sec": 60,
"update_check_interval_sec": 3600
}
}
Field reference for terminal_parameters (acquirers, CA keys, EMV kernels): Terminal Parameters.
Response Fields
terminal
| Field | Type | Description |
|---|---|---|
terminal_id | string | Terminal key assigned to this device |
device_id | string | Physical device identifier |
merchant
| Field | Type | Description |
|---|---|---|
merchant_key | string | Unique merchant key |
name | string | Merchant business name |
tip_info | object | Optional. Tip settings copied from merchants.tip_info (JSON). Omitted when unset or empty. Example shape: tip_type, tip_label, tip_enabled, tip_description, allow_custom_tip, maximum_tip_amount, minimum_tip_amount, suggested_tip_amounts, default_tip_percentage, suggested_tip_percentages (same structure as the back-office merchant tip profile). |
tax_info | object | Optional. Tax settings copied from merchants.tax_info (JSON). Omitted when unset or empty. Example shape: tax_rate, tax_number, tax_region, tax_enabled, tax_inclusive, liability_accepted (same structure as the back-office merchant tax profile). |
surcharge_info | object | Optional. Surcharge settings copied from merchants.surcharge_info (JSON). Omitted when unset or empty. Example shape: surcharge_type, surcharge_label, surcharge_enabled, liability_accepted, surcharge_percentage, surcharge_description, surcharge_fixed_amount, maximum_surcharge_amount, apply_to_credit_cards_only, minimum_transaction_amount (same structure as the back-office merchant surcharge profile). |
location
| Field | Type | Description |
|---|---|---|
name | string | Location name (empty if not assigned) |
timezone | string | IANA timezone (defaults to UTC) |
security
| Field | Type | Description |
|---|---|---|
pin_required | boolean | Whether PIN entry is required |
online_pin | boolean | Whether online PIN verification is used |
contactless_limit_minor | integer | Contactless limit in minor units (e.g., 5000 = $50.00) |
fallback_allowed | boolean | Whether magnetic stripe fallback is permitted |
emv
| Field | Type | Description |
|---|---|---|
aid_list | string[] | Supported Application Identifiers (Visa, MasterCard, Amex) |
terminal_capabilities | string | EMV terminal capabilities (hex) |
additional_terminal_capabilities | string | Additional capabilities (hex) |
terminal_type | string | EMV terminal type code |
application_version_number | string | EMV application version |
branding
| Field | Type | Description |
|---|---|---|
theme | string | UI theme (dark or light) |
logo | string | URL to the merchant/reseller logo |
device_config
| Field | Type | Description |
|---|---|---|
heartbeat_interval_sec | integer | How often to send heartbeats (seconds) |
update_check_interval_sec | integer | How often to check for firmware updates (seconds) |
401 Unauthorized
{
"error": {
"code": "4001",
"message": "Invalid or expired attestation token",
"trace_id": "abc123..."
}
}
404 Not Found
{
"error": {
"code": "4004",
"message": "Device not found",
"details": {
"device_id": "POS-UNKNOWN"
},
"trace_id": "abc123..."
}
}
Code Examples
The API returns an MSK envelope, not plain JSON. Samples below show the HTTP call; after receiving the response, run MSK decrypt on the envelope to obtain the core config object. Then call Terminal Parameters and merge. See End-to-End Example.
- cURL
- Python
- Ruby
- Go
- C#
- PHP
- Java
curl -X POST https://api.viopay.io/pos/config \
-H "Authorization: Attestation att_f83kLmP9s2ab" \
-H "X-Device-Id: POS-8F3A2C91" \
-H "Content-Type: application/json"
import requests
url = "https://api.viopay.io/pos/config"
headers = {
"Authorization": "Attestation att_f83kLmP9s2ab",
"X-Device-Id": "POS-8F3A2C91",
"Content-Type": "application/json",
}
response = requests.post(url, headers=headers)
envelope = response.json()
# config = msk_decrypt(envelope) # use your MSK from POST /pos/keys
print(f"Envelope format: {envelope['format']}")
print(f"MSK KCV: {envelope.get('key_kcv')}")
require 'net/http'
require 'json'
require 'uri'
uri = URI("https://api.viopay.io/pos/config")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Attestation att_f83kLmP9s2ab"
request["X-Device-Id"] = "POS-8F3A2C91"
request["Content-Type"] = "application/json"
response = http.request(request)
envelope = JSON.parse(response.body)
puts "Envelope format: #{envelope['format']}"
puts "MSK KCV: #{envelope['key_kcv']}"
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("POST", "https://api.viopay.io/pos/config", nil)
req.Header.Set("Authorization", "Attestation att_f83kLmP9s2ab")
req.Header.Set("X-Device-Id", "POS-8F3A2C91")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var envelope map[string]interface{}
json.Unmarshal(body, &envelope)
fmt.Printf("Envelope format: %v\n", envelope["format"])
fmt.Printf("MSK KCV: %v\n", envelope["key_kcv"])
// config := mskDecrypt(envelope)
}
using System.Net.Http;
using System.Text.Json;
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.viopay.io/pos/config");
request.Headers.Add("Authorization", "Attestation att_f83kLmP9s2ab");
request.Headers.Add("X-Device-Id", "POS-8F3A2C91");
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
var envelope = JsonSerializer.Deserialize<JsonElement>(body);
Console.WriteLine($"Envelope format: {envelope.GetProperty("format")}");
Console.WriteLine($"MSK KCV: {envelope.GetProperty("key_kcv")}");
// var config = MskDecrypt(envelope);
<?php
$ch = curl_init("https://api.viopay.io/pos/config");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Attestation att_f83kLmP9s2ab",
"X-Device-Id: POS-8F3A2C91",
"Content-Type: application/json",
],
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
echo "Envelope format: " . $data["format"] . "\n";
echo "MSK KCV: " . $data["key_kcv"] . "\n";
// $config = msk_decrypt($data);
import java.net.http.*;
import java.net.URI;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.viopay.io/pos/config"))
.POST(HttpRequest.BodyPublishers.noBody())
.header("Authorization", "Attestation att_f83kLmP9s2ab")
.header("X-Device-Id", "POS-8F3A2C91")
.header("Content-Type", "application/json")
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
What's Next?
After MSK-decrypting the core config, fetch and merge Terminal Parameters, then activate the device:
Next step → Terminal Parameters → Activate
See also: End-to-End Example steps 7a–8.