Rox Verify API
Integrate KYC & KYB identity verification into your application. REST + JSON, authenticated with HMAC request signing.
Base URL — https://platform.roxverify.io/api/v1
API keys
Keys are created inside your Rox Verify account.
Sign in at platform.roxverify.io → Integration, and generate a credential. Each credential is a public Key + a Secret. The secret is shown once — store it securely; it never travels over the network and is used only to sign requests. Credentials are scoped to the abilities you select (kyc:create, kyc:read, kyc:pdf, and the kyb:* equivalents).
Authentication (HMAC request signing)
Send these headers on every request:
X-Api-Key: <your key>
X-Api-Timestamp: <unix seconds> # must be within 5 minutes
X-Api-Signature: <hex HMAC-SHA256>
The signature is HMAC-SHA256 of the following string, using your secret as the key:
{METHOD}\n{REQUEST_PATH}\n{TIMESTAMP}\n{sha256_hex(body)}
# e.g. POST /api/v1/sessions
POST\n/api/v1/sessions\n1750000000\n<sha256 of the JSON body>
Ready-to-use Node.js helper:
const crypto = require('crypto');
const KEY = 'rk_live_...'; // X-Api-Key
const SECRET = 'rsk_...'; // never sent — signs requests
const BASE = 'https://platform.roxverify.io/api/v1';
// Build the signed headers for a request
function sign(method, path, body = '') {
const ts = Math.floor(Date.now() / 1000).toString();
const bodyHash = crypto.createHash('sha256').update(body).digest('hex');
const signingString = [method.toUpperCase(), path, ts, bodyHash].join('\n');
const signature = crypto.createHmac('sha256', SECRET).update(signingString).digest('hex');
return {
'X-Api-Key': KEY,
'X-Api-Timestamp': ts,
'X-Api-Signature': signature,
'Content-Type': 'application/json',
'Accept': 'application/json',
};
}
// Create a verification session
const body = JSON.stringify({ client_name: 'Jane Cooper', vendor_data: 'user-123' });
const path = '/api/v1/sessions';
fetch(BASE + '/sessions', { method: 'POST', headers: sign('POST', path, body), body })
.then(r => r.json()).then(console.log);
Requests with a missing/invalid signature, or a timestamp older than 5 minutes, are rejected with 401 — so an intercepted request can’t be replayed or modified.
1 · Create a verification session
Creates a user (KYC) session and returns a hosted URL to send to your client.
{ "client_name": "Jane Cooper", "client_email": "jane@example.com", "vendor_data": "user-123" }
→ { "id": 42, "type": "user", "status": "Not Started", "session_url": "https://verify.roxverify.io/session/AbC123" }
To open a business verification (KYB) session instead, pass "type": "business" (requires the kyb:create ability):
{ "type": "business", "company_name": "Sellsides Ltd", "company_website": "sellsides.com", "vendor_data": "company-123" }
→ { "id": 51, "type": "business", "status": "Not Started", "session_url": "https://verify.roxverify.io/session/XyZ789" }
company_website (or a company email) is optional — it’s used to show the business logo on the verification.
2 · Get status & extracted data
Overall status, per-check results, and the extracted identity once your client finishes — so you get more than just Approved / Declined.
{
"id": 42, "type": "user", "status": "Approved",
"checks": { "id_verification": "Approved", "liveness": "Approved", "face_match": "Approved",
"aml": "Approved", "ip_analysis": "Approved",
"proof_of_address": "Approved", "email": "Approved", "phone": "Approved" },
"identity": {
"first_name": "James", "last_name": "Whitfield", "full_name": "James Whitfield",
"date_of_birth": "1988-04-17", "nationality": "GBR",
"country": "United Kingdom", "country_code": "GBR",
"country_code_alpha2": "GB", "country_flag": "🇬🇧",
"document_type": "Passport",
"document_number": "533401372",
"id_number_type": "passport_number", // national_id_number | residence_number | ...
"passport_number": "533401372", // same value, under its type-specific key
"address": "221B Baker Street, London, NW1 6XE"
},
// The three blocks below appear ONLY when your workflow runs that step:
"address_verification": { "verified": true, "status": "Approved",
"address": "221B Baker Street, London, NW1 6XE",
"document_type": "Bank Statement" },
"email_verification": { "email": "james@example.com", "verified": true, "status": "Approved" },
"phone_verification": { "phone_number": "+44 7700 900123", "verified": true, "status": "Approved" },
"charged_services": ["kyc","liveness","aml","ip"]
}
identityis returned as soon as an ID document has been read.id_number_typetells you whether the ID number is apassport_number,national_id_number,residence_numberordriving_license_number; the same value is also repeated under that key.country_flag(emoji) andcountry_code_alpha2are derived from the issuing country for easy display.address_verification,email_verificationandphone_verificationare present only when your workflow includes those steps — each carries a booleanverifiedflag.
3 · Get the full decision
Everything from the status call above (identity + the verification blocks) plus the complete raw decision — document data, biometric scores, AML hits, IP / device.
4 · Download the report PDF
Returns the official report as a PDF (application/pdf).
Webhooks (optional)
Instead of polling, Rox Verify will POST the verified event to your endpoint when a session reaches a final status. Configure your receiving URL in your account under Integration → Webhooks.
Each webhook is signed the same way as API responses, so you can verify it genuinely came from Rox Verify before trusting it.
KYB (kyb:*) endpoints mirror the KYC ones and are available when business verification is enabled on your account.