KXCO Chain

Developer Integration Spec

For licensed bank operators integrating KXCO settlement rails into their consumer product.

Base URL: https://api.kxco.io/v1Version: v1Format: JSONAuth: Bearer + ML-DSA-65

1. Authentication

All institution API calls require a Bearer token in the Authorization header. Post-quantum ML-DSA-65 signing is available for enhanced security.

Bearer Token

GET /api/v1/payments HTTP/1.1
Host: api.kxco.io
Authorization: Bearer kxco_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

ML-DSA-65 (Post-Quantum) — per-request signing

POST /api/v1/payments HTTP/1.1
Authorization: Bearer kxco_live_xxxx
X-KXCO-Timestamp: 1748000000
X-KXCO-Signature: <ML-DSA-65 signature of "timestamp.method.path.body_hash">
Content-Type: application/json

Register your ML-DSA public key

POST /api/admin/institutions/:id/ml-dsa
{
  "publicKey": "<1952-byte ML-DSA-65 public key, hex-encoded>"
}

2. Payment Instructions

Submit cross-currency payment instructions. KXCO handles FX rate locking and ARMR settlement. Your consumer app calls your backend; your backend calls KXCO.

Initiate a payment

POST /api/v1/payments
{
  "endToEndId": "E2E-2026-001",
  "debtor": {
    "name":    "Jane Smith",
    "account": "KXCO-ACC-20260101-AABBCC",
    "agent":   "YOURBANK"
  },
  "creditor": {
    "name":    "Supplier Co Ltd",
    "account": "KXCO-ACC-20260101-XXYYZZ",
    "agent":   "PARTNERBANK"
  },
  "amount": {
    "currency": "USD",
    "value":    "10000.00"
  },
  "remittanceInfo": "Invoice #2026-089"
}

Response

{
  "uetr":      "550e8400-e29b-41d4-a716-446655440000",
  "txRef":     "KXCO-PMNT-20260518-AB12CD",
  "status":    "INITIATED",
  "riskHeld":  false,
  "createdAt": "2026-05-18T10:22:00.000Z"
}

Payment lifecycle

StatusMeaningNext action
INITIATEDCreated, pending admin validationAdmin: validate
VALIDATEDValidated, awaiting rate lockAdmin: apply-rate
RATE_LOCKEDRate locked, ready to settleAdmin: settle
PENDING_SETTLEMENTSettlement in progressAutomatic
SETTLEDFunds transferred, ledger updatedTerminal
FAILEDPayment rejectedTerminal
RETURNEDSettled then returned (FOCR / NARR)Terminal

3. Webhooks

Register HTTPS endpoints to receive real-time payment events. Every delivery carries two independent signatures: a classical HMAC-SHA-256 for compatibility, and a post-quantum ML-DSA-65 signature (NIST FIPS 204) for non-repudiation.

Register an endpoint

POST /api/admin/institutions/:id/webhooks
{
  "url":    "https://yourbank.com/webhooks/kxco",
  "events": ["payment.settled", "payment.failed", "payment.returned"]
}

Request headers on delivery

HeaderValue
Content-Typeapplication/json
X-KXCO-Eventpayment.settled
X-KXCO-Timestamp1748000000 (Unix seconds)
X-KXCO-Signaturesha256=<HMAC-SHA-256 hex>
X-KXCO-PQ-Signatureml-dsa-65=<6618 hex chars>
X-KXCO-PQ-Kid<16-hex platform-key fingerprint>
X-KXCO-Delivery<job-id UUID>

Verifying either signature alone is sufficient. Verifying both gives defence-in-depth: HMAC blocks tampering by any party who knows the shared secret, and ML-DSA-65 cryptographically binds the message to the KXCO platform identity even if the HMAC secret is ever leaked.

Fetch the platform public key (one-time, pin and cache)

GET /wallet/api/.well-known/kxco-pq-pubkey

// Response
{
  "alg":         "ML-DSA-65",
  "spec":        "NIST FIPS 204",
  "publicKey":   "<3904 hex chars = 1952 bytes>",
  "kid":         "aa29f37ab7f4b2cf",
  "sigEncoding": "hex",
  "msgFormat":   "{X-KXCO-Timestamp}.{raw_request_body}"
}

Pin the public key in your config and treat the kid as the active key identifier. If you receive a delivery with an unexpected kid, refresh the well-known endpoint.

Verify the classical HMAC signature (Node.js)

const crypto = require('crypto')

function verifyHmac(secret, timestamp, rawBody, sigHeader) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${rawBody}`)
    .digest('hex')
  return crypto.timingSafeEqual(
    Buffer.from(sigHeader),
    Buffer.from(expected)
  )
}

Verify the post-quantum signature — recommended (Node.js)

// npm install kxco-post-quantum
const { webhook } = require('kxco-post-quantum')

const PINNED_KID    = 'aa29f37ab7f4b2cf'                     // current KXCO production kid
const PINNED_PUBKEY = Buffer.from('...3904 hex chars...', 'hex')

function verify(req) {
  const headers = Object.fromEntries(
    Object.entries(req.headers).map(([k, v]) => [k.toLowerCase(), v])
  )
  const r = webhook.verifyDelivery({
    headers,
    rawBody:     req.rawBody,        // byte-for-byte exactly as received
    pqPublicKey: PINNED_PUBKEY,
    pinnedKid:   PINNED_KID,
  })
  return r.pqOk && r.timestampOk && r.kidOk
}

The same package handles HMAC verification, kid pinning, and the timestamp replay window. Source: npmjs.com/package/kxco-post-quantum.

Or use any FIPS 204 implementation directly

// npm install @noble/post-quantum
const { ml_dsa65 } = require('@noble/post-quantum/ml-dsa')

function verifyPq(headers, rawBody) {
  if (headers['x-kxco-pq-kid'] !== PINNED_KID) return false
  const sig = headers['x-kxco-pq-signature'].replace(/^ml-dsa-65=/, '')
  const ts  = headers['x-kxco-timestamp']
  if (Math.abs(Date.now() / 1000 - parseInt(ts, 10)) > 300) return false
  const msg = Buffer.from(`${ts}.${rawBody}`, 'utf8')
  return ml_dsa65.verify(PINNED_PUBKEY, msg, Buffer.from(sig, 'hex'))
}

Works with @noble/post-quantum, liboqs, the BoringSSL PQ branch, or any FIPS 204 implementation.

Example payload — payment.settled

{
  "event":          "payment.settled",
  "uetr":           "550e8400-e29b-41d4-a716-446655440000",
  "txRef":          "KXCO-PMNT-20260518-AB12CD",
  "instrAmt":       10000.00,
  "instrAmtCcy":    "USD",
  "settlAmt":       8471.23456789,
  "onChainTxHash":  "0xabc123...",
  "sttlmTm":        "2026-05-18T10:35:00.000Z"
}

Retry policy

AttemptDelay after failure
1Immediate
230 seconds
35 minutes
430 minutes
52 hours — then marked DEAD

Available events

EventFired when
payment.initiatedPayment instruction created
payment.rate_lockedRate locked, settlAmt confirmed
payment.settledFunds transferred, ledger updated
payment.failedPayment rejected at any stage
payment.returnedSettled payment returned to sender
*Subscribe to all events

4. Rate Locks

An admin creates a rate lock before a payment is settled. The rate is guaranteed for the lock's validity window (default 60 minutes). Your consumer app should display the rate to the user before they confirm.

POST /api/admin/rates
{
  "institutionCode": "YOURBANK",
  "fromCcy":         "USD",
  "toCcy":           "ARMR",
  "rate":            0.84712,
  "inverseRate":     1.18046,
  "midRate":         0.84700,
  "expiresInMinutes": 60
}

// Response
{
  "id":        "clxyz...",
  "rate":      0.84712,
  "expiresAt": "2026-05-18T11:22:00.000Z"
}

5. Consumer PWA Integration

The KXCO consumer PWA is deployed at /wallet/app. The bank registers customers using their institution code and the customers transact in a fully branded mobile-first interface.

Customer registration flow

POST /api/app/auth/register
{
  "name":            "Jane Smith",
  "email":           "jane@example.com",
  "phone":           "+44 7700 000000",
  "password":        "••••••••",
  "institutionCode": "YOURBANK"   // your 8-char BIC-style code
}

// On success: session cookie set, redirect to /app/home

Consumer API endpoints

MethodEndpointDescription
POST/api/app/auth/loginCustomer sign-in — returns session cookie
POST/api/app/auth/registerRegister with institution code
GET/api/app/meProfile + all currency balances
POST/api/app/sendP2P transfer to another registered user
POST/api/app/exchangeIn-app FX conversion (uses KXCO rate lock)
GET/api/app/transactionsPaginated transaction history

PWA routes

RouteScreen
/wallet/app/loginSign in
/wallet/app/registerCreate account
/wallet/app/homeBalance overview + recent transactions
/wallet/app/sendSend money to another user
/wallet/app/exchangeFX currency conversion
/wallet/app/historyFull transaction history
/wallet/app/cardCard management (Mastercard — coming soon)
/wallet/app/profileAccount details + sign out

6. Sandbox Environment

Each client institution is provisioned with a sandboxed environment on request. All data is isolated. Rate locks, payments, and balances are independent from production.

# Sandbox base URL (provided per client)
https://sandbox-<client>.chain.kxco.ai/wallet/api

# Test institution code
TESTBANK

# Test bearer token
kxco_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Contact enterprise@knightsbridge.asia to request sandbox access.

7. Error Codes

HTTPMeaningCommon cause
400Bad RequestMissing required fields or invalid state transition
401UnauthorisedMissing or invalid Bearer token
403ForbiddenToken valid but insufficient permissions
404Not FoundUnknown UETR, institution code, or account
405Method Not AllowedWrong HTTP method for this endpoint
409ConflictDuplicate endToEndId or idempotency key
429Rate LimitedExceeded RPM limit for institution
500Server ErrorContact support with X-KXCO-Delivery header