Activate
The final step in the POS activation flow. The device reports that encryption keys are installed, EMV is ready, and the network connection is stable. After successful activation, the device status changes to activated and it can begin processing payments. This is the eighth and final step in the POS activation flow.
MSK encryption: Both the request and response use MSK-encrypted envelopes (TR31-DATA). Encrypt the activation JSON with MSK before sending; decrypt the response with MSK to read status and activated_at.
Purpose
- Confirm that the device has successfully installed encryption keys
- Confirm that EMV configuration is loaded and ready
- Confirm that the network connection is stable
- Transition the device status from
claimedtoactivated - Record the activation timestamp
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 — MSK-encrypted envelope
Encrypt the activation payload below with MSK (AES-256-CBC) and send the envelope:
{
"format": "TR31-DATA",
"ciphertext": "A1B2C3...",
"initialization_vector": "000102030405060708090A0B0C0D0E0F",
"mode": "CBC"
}
Plaintext (before MSK encrypt)
{
"emv_ready": true,
"keys_installed": true,
"network_ok": true
}
| Field | Type | Required | Description |
|---|---|---|---|
emv_ready | boolean | Yes | Whether EMV configuration has been loaded |
keys_installed | boolean | Yes | Whether encryption keys have been installed and verified |
network_ok | boolean | Yes | Whether the network connection is stable |
All three fields should be true for successful activation. The device should verify these conditions locally before calling this endpoint.
Response
200 OK — MSK-encrypted envelope
Decrypt with MSK to obtain:
{
"status": "activated",
"activated_at": "2025-12-13T14:30:00Z"
}
Wire format:
{
"format": "TR31-DATA",
"ciphertext": "D4E5F6...",
"initialization_vector": "101112131415161718191A1B1C1D1E1F",
"mode": "CBC",
"key_kcv": "ABCD12"
}
| Field | Type | Description |
|---|---|---|
status | string | Always "activated" on success (after decrypt) |
activated_at | string | Activation timestamp in RFC3339 format (after decrypt) |
400 Bad Request
{
"error": {
"code": "4000",
"message": "Invalid request body",
"details": {
"message": "Key: 'POSActivateRequest.EMVReady' Error:Field validation..."
},
"trace_id": "abc123..."
}
}
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
Encrypt the activation JSON with MSK before sending; decrypt the response envelope. Samples below show plaintext for clarity — wrap in TR31-DATA on the wire. See End-to-End Example.
- cURL
- Python
- Ruby
- Go
- C#
- PHP
- Java
curl -X POST https://api.viopay.io/pos/activate \
-H "Authorization: Attestation att_f83kLmP9s2ab" \
-H "X-Device-Id: POS-8F3A2C91" \
-H "Content-Type: application/json" \
-d '{
"emv_ready": true,
"keys_installed": true,
"network_ok": true
}'
import requests
url = "https://api.viopay.io/pos/activate"
headers = {
"Authorization": "Attestation att_f83kLmP9s2ab",
"X-Device-Id": "POS-8F3A2C91",
"Content-Type": "application/json",
}
payload = {
"emv_ready": True,
"keys_installed": True,
"network_ok": True,
}
response = requests.post(url, json=payload, headers=headers)
data = response.json()
print(f"Status: {data['status']}")
print(f"Activated at: {data['activated_at']}")
require 'net/http'
require 'json'
require 'uri'
uri = URI("https://api.viopay.io/pos/activate")
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"
request.body = {
emv_ready: true,
keys_installed: true,
network_ok: true
}.to_json
response = http.request(request)
data = JSON.parse(response.body)
puts "Status: #{data['status']}"
puts "Activated at: #{data['activated_at']}"
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
type ActivateRequest struct {
EMVReady bool `json:"emv_ready"`
KeysInstalled bool `json:"keys_installed"`
NetworkOK bool `json:"network_ok"`
}
type ActivateResponse struct {
Status string `json:"status"`
ActivatedAt string `json:"activated_at"`
}
func main() {
payload, _ := json.Marshal(ActivateRequest{
EMVReady: true,
KeysInstalled: true,
NetworkOK: true,
})
req, _ := http.NewRequest("POST", "https://api.viopay.io/pos/activate", bytes.NewBuffer(payload))
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 result ActivateResponse
json.Unmarshal(body, &result)
fmt.Printf("Status: %s\n", result.Status)
fmt.Printf("Activated at: %s\n", result.ActivatedAt)
}
using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
var payload = new
{
emv_ready = true,
keys_installed = true,
network_ok = true
};
var content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.viopay.io/pos/activate");
request.Headers.Add("Authorization", "Attestation att_f83kLmP9s2ab");
request.Headers.Add("X-Device-Id", "POS-8F3A2C91");
request.Content = content;
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
var data = JsonSerializer.Deserialize<JsonElement>(body);
Console.WriteLine($"Status: {data.GetProperty("status")}");
Console.WriteLine($"Activated at: {data.GetProperty("activated_at")}");
<?php
$ch = curl_init("https://api.viopay.io/pos/activate");
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",
],
CURLOPT_POSTFIELDS => json_encode([
"emv_ready" => true,
"keys_installed" => true,
"network_ok" => true,
]),
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
echo "Status: " . $data["status"] . "\n";
echo "Activated at: " . $data["activated_at"] . "\n";
import java.net.http.*;
import java.net.URI;
HttpClient client = HttpClient.newHttpClient();
String payload = """
{
"emv_ready": true,
"keys_installed": true,
"network_ok": true
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.viopay.io/pos/activate"))
.POST(HttpRequest.BodyPublishers.ofString(payload))
.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?
The device is now activated and ready to process payments using HMAC signature authentication and MSK-encrypted charge payloads:
- End-to-End Example — full charge walkthrough
- Create POS Charge —
POST /pos/charge - Refund POS Charge —
POST /pos/charge/:chargeID/refund - Cancel POS Charge —
POST /pos/charge/:chargeID/cancel
See the POS Device Overview for a recap of the complete activation flow.