REST API
The KnightsVault REST API provides programmatic access to accounts, statements, and transfers. All endpoints require an API key issued by a platform administrator.
Base URL & Authentication
Base URL
https://chain.kxco.ai/wallet/api/v1Option A — Bearer token
Include an Authorization header with a Bearer token issued by a platform administrator. The raw token is shown once at creation and cannot be recovered.
Authorization: Bearer kxco_<your-api-key>
Option B — ML-DSA-65 signed request (post-quantum)
Institutional API clients may authenticate using per-request ML-DSA-65 signatures (NIST FIPS 204). The client generates a keypair locally, registers only the public key with a platform administrator, and signs each request with the private key. The server stores no secret — only the public key.
# Header format
Authorization: KXCO-MLDSA <pubkey_hex>.<timestamp_ms>.<sig_hex>
# Signed message (UTF-8 encoded)
"<timestamp_ms>:<METHOD>:<request_path>"
# Example (Node.js, using @noble/post-quantum)
import { ml_dsa65 } from '@noble/post-quantum/ml-dsa'
const ts = Date.now().toString()
const msg = Buffer.from(`${ts}:GET:/api/v1/accounts/clxxxx`, 'utf8')
const sig = ml_dsa65.sign(secretKey, msg)
// Authorization: KXCO-MLDSA <pubkey_hex>.<ts>.<hex(sig)>Timestamp must be within ±30 seconds of server time. Public keys are registered via the Back Office (Back Office → API Keys → Register ML-DSA Key).
Errors
All errors return JSON with an error field.
| Status | Meaning |
|---|---|
| 401 | Missing or invalid API key |
| 403 | Key does not have permission for this operation |
| 404 | Resource not found |
| 400 | Bad request — see error field for detail |
| 429 | Rate limit exceeded (10 req/s per IP) |
| 500 | Internal error |
Accounts
/accounts/{id}Retrieve account detailsReturns account details for the given account ID. id is the internal CUID (returned in the reference field of list responses).
curl -s "https://chain.kxco.ai/wallet/api/v1/accounts/clxxxx" \ -H "Authorization: Bearer kxco_<key>"
{
"id": "clxxxx",
"reference": "KXCO-ABCD-1234",
"email": "client@institution.com",
"status": "approved",
"dailyLimit": 50000,
"singleLimit": 10000,
"address": "0xabc...def",
"balance": "12450.00"
}/accounts/{id}/statementPaginated transaction statementReturns a paginated transaction history for the account.
| Parameter | Type | Description |
|---|---|---|
| page | integer | Page number, 1-based. Default: 1 |
| limit | integer | Records per page. Max 200. Default: 50 |
{
"total": 142,
"page": 1,
"limit": 50,
"transactions": [
{
"txRef": "TXN20260515-A1B2C3D4",
"txHash": "0xabc...",
"direction": "out",
"amount": "1000.00",
"toAddress": "0xdef...",
"status": "confirmed",
"blockNumber": 40120,
"timestamp": 1778900000,
"createdAt": "2026-05-15T10:00:00.000Z"
}
]
}Transfers
/transfersList transfersReturns a paginated list of transfers. Optionally filtered by account.
| Parameter | Type | Description |
|---|---|---|
| accountId | string | Filter by account ID. Optional. |
| page | integer | Page number, 1-based. Default: 1 |
| limit | integer | Records per page. Max 200. Default: 50 |
/transfersInitiate a transferInitiates an ARMR transfer from the specified account. Signing is performed server-side using the account's encrypted private key — no password or key material is required in the request.
{
"fromAccountId": "clxxxx",
"to": "0xRecipientAddress",
"amount": "1000.00",
"memo": "INV-2026-001"
}memo is optional (max 512 chars). When the recipient is on the KnightsVault platform, the memo is encrypted with their ML-KEM-768 public key before being embedded in the transaction data field — chain observers cannot read it.
{
"ok": true,
"txRef": "TXN20260515-A1B2C3D4",
"txHash": "0xabc...",
"status": "pending"
}failed — it will not be retried automatically. Check the transfer status before re-submitting./transfers/{reference}Get transfer by referenceRetrieves a single transfer by its txRef (format: TXNYYYYMMDD-XXXXXXXX).
curl -s "https://chain.kxco.ai/wallet/api/v1/transfers/TXN20260515-A1B2C3D4" \ -H "Authorization: Bearer kxco_<key>"
{
"txRef": "TXN20260515-A1B2C3D4",
"txHash": "0xabc...",
"fromAddress": "0xsender...",
"toAddress": "0xrecipient...",
"amount": "1000.00",
"direction": "out",
"status": "confirmed",
"blockNumber": 40120,
"timestamp": 1778900000,
"createdAt": "2026-05-15T10:00:00.000Z"
}Webhooks
KXCO delivers real-time payment events to HTTPS endpoints registered by the institution. Each delivery is signed with HMAC-SHA256 using a shared secret set by the platform administrator.
Event types
| payment.initiated | Payment instruction received and persisted |
| payment.rate_locked | Exchange rate locked — settlement amount fixed |
| payment.settled | On-chain settlement confirmed |
| payment.failed | Payment failed — see failRsn in payload |
| payment.returned | Payment returned to sender |
Request headers
X-KXCO-Signature: sha256=<hmac_hex> X-KXCO-Event: payment.settled X-KXCO-Timestamp: 1778900000 X-KXCO-Delivery: <job_id>
Signature verification (Node.js)
const crypto = require('crypto')
function verify(secret, timestamp, rawBody, sigHeader) {
const expected = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`)
.digest('hex')
const received = sigHeader.replace('sha256=', '')
return crypto.timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(received, 'hex')
)
}Reject deliveries where the timestamp is more than 5 minutes old to prevent replay attacks. Always use timingSafeEqual — never a string equality check.
Example payload — payment.settled
{
"event": "payment.settled",
"uetr": "550e8400-e29b-41d4-a716-446655440000",
"txRef": "KXCO-PMNT-20260515-A1B2C3",
"status": "SETTLED",
"instrAmtCcy": "USD",
"instrAmt": 10000.00,
"settlAmtCcy": "ARMR",
"settlAmt": 42500.00,
"onChainTxHash": "0xabc...",
"sttlmTm": "2026-05-15T10:00:00.000Z",
"dbtrInst": "KXCOBHBH",
"cdtrInst": "KXCODKDK"
}Retry policy
| Attempt | Delay after failure |
|---|---|
| 1 | Immediate |
| 2 | 30 seconds |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours — final attempt, then DEAD |
Your endpoint must return a 2xx status within 10 seconds. Any other response or timeout is treated as a failure and retried.
Banking Integration
/bank/connectISO 20022 integrationReturns integration instructions for connecting a correspondent banking system via ISO 20022 pacs.008 (FI-to-FI credit transfer). This endpoint documents the expected message format and field mappings for settlement instruction routing.
curl -s -X POST "https://chain.kxco.ai/wallet/api/v1/bank/connect" \
-H "Authorization: Bearer kxco_<key>" \
-H "Content-Type: application/json" \
-d '{"institutionBIC":"XXXXGB2L","accountId":"clxxxx"}'To request an API key or discuss integration requirements, contact the KXCO engineering team.