Claim Device
Claims a POS device by entering the pairing code displayed on the device screen. This endpoint is called from the merchant web portal (not the POS device itself). It links the physical device to the merchant's account. This is the fourth step in the POS activation flow.
Purpose
- Merchant enters the 6-character pairing code from the POS screen into the backoffice portal
- Validates the pairing code is not expired and not already used
- Verifies the device belongs to the merchant's account
- Marks the pairing code as used and updates the device status to
claimed
Authentication
Bearer Token — Keycloak JWT. The merchant must be logged in to the backoffice portal.
| Header | Required | Format | Description |
|---|---|---|---|
Authorization | Yes | Bearer {jwt_token} | 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. The merchant context is resolved from the token. Example: Bearer eyJhbGciOiJSUzI1NiIs... |
Content-Type | Yes | application/json | Request body format. Always application/json. |
Unlike other POS endpoints, this is called by the merchant from the web portal, not by the POS device itself. The merchant must be authenticated with a Bearer token, and the device being claimed must belong to the merchant's account.
See the Headers Reference for complete details.
Request
{
"pairing_code": "K7M3NP"
}
| Field | Type | Required | Description |
|---|---|---|---|
pairing_code | string | Yes | The 6-character code displayed on the POS device screen |
Response
200 OK
{
"status": "claimed",
"device_id": "POS-8F3A2C91"
}
| Field | Type | Description |
|---|---|---|
status | string | Always "claimed" on success |
device_id | string | The device ID that was claimed |
400 Bad Request — Invalid or Missing Code
{
"error": {
"code": "4000",
"message": "Invalid request body",
"details": {
"message": "Key: 'ClaimDeviceRequest.PairingCode' Error:Field validation for 'PairingCode' failed on the 'required' tag"
},
"trace_id": "abc123..."
}
}
400 Bad Request — Code Not Found
{
"error": {
"code": "4004",
"message": "Pairing code not found",
"details": {
"pairing_code": "XXXXXX"
},
"trace_id": "abc123..."
}
}
400 Bad Request — Code Expired
{
"error": {
"code": "4220",
"message": "Pairing code has expired",
"details": {
"pairing_code": "K7M3NP"
},
"trace_id": "abc123..."
}
}
400 Bad Request — Code Already Used
{
"error": {
"code": "4220",
"message": "Pairing code has already been used",
"details": {
"pairing_code": "K7M3NP"
},
"trace_id": "abc123..."
}
}
403 Forbidden — Device Not Owned
{
"error": {
"code": "4003",
"message": "Device does not belong to your merchant account",
"details": {
"device_id": "POS-8F3A2C91"
},
"trace_id": "abc123..."
}
}
Code Examples
- cURL
- Python
- Ruby
- Go
- C#
- PHP
- Java
curl -X POST https://api.viopay.io/pos/claim \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{"pairing_code": "K7M3NP"}'
import requests
url = "https://api.viopay.io/pos/claim"
headers = {
"Authorization": "Bearer eyJhbGciOiJSUzI1NiIs...",
"Content-Type": "application/json",
}
payload = {
"pairing_code": "K7M3NP"
}
response = requests.post(url, json=payload, headers=headers)
data = response.json()
print(f"Status: {data['status']}")
print(f"Device ID: {data['device_id']}")
require 'net/http'
require 'json'
require 'uri'
uri = URI("https://api.viopay.io/pos/claim")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer eyJhbGciOiJSUzI1NiIs..."
request["Content-Type"] = "application/json"
request.body = { pairing_code: "K7M3NP" }.to_json
response = http.request(request)
data = JSON.parse(response.body)
puts "Status: #{data['status']}"
puts "Device ID: #{data['device_id']}"
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
type ClaimRequest struct {
PairingCode string `json:"pairing_code"`
}
type ClaimResponse struct {
Status string `json:"status"`
DeviceID string `json:"device_id"`
}
func main() {
payload, _ := json.Marshal(ClaimRequest{PairingCode: "K7M3NP"})
req, _ := http.NewRequest("POST", "https://api.viopay.io/pos/claim", bytes.NewBuffer(payload))
req.Header.Set("Authorization", "Bearer eyJhbGciOiJSUzI1NiIs...")
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 ClaimResponse
json.Unmarshal(body, &result)
fmt.Printf("Status: %s\n", result.Status)
fmt.Printf("Device ID: %s\n", result.DeviceID)
}
using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer eyJhbGciOiJSUzI1NiIs...");
var payload = new { pairing_code = "K7M3NP" };
var content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://api.viopay.io/pos/claim", content);
var body = await response.Content.ReadAsStringAsync();
var data = JsonSerializer.Deserialize<JsonElement>(body);
Console.WriteLine($"Status: {data.GetProperty("status")}");
Console.WriteLine($"Device ID: {data.GetProperty("device_id")}");
<?php
$ch = curl_init("https://api.viopay.io/pos/claim");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer eyJhbGciOiJSUzI1NiIs...",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode(["pairing_code" => "K7M3NP"]),
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
echo "Status: " . $data["status"] . "\n";
echo "Device ID: " . $data["device_id"] . "\n";
import java.net.http.*;
import java.net.URI;
HttpClient client = HttpClient.newHttpClient();
String payload = "{\"pairing_code\": \"K7M3NP\"}";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.viopay.io/pos/claim"))
.POST(HttpRequest.BodyPublishers.ofString(payload))
.header("Authorization", "Bearer eyJhbGciOiJSUzI1NiIs...")
.header("Content-Type", "application/json")
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
What's Next?
Once the device is claimed, the POS device (which has been polling /pos/status) will detect is_claimed: true and proceed to attest its identity:
Next step → Attest