Skip to content

Kyriba

DPX integrates with Kyriba in two modes:

ModeWho initiatesBest for
Payment Initiation SPIKyriba calls DPXKyriba Connect Marketplace certified connector — Kyriba-native flow
Direct Integration APIKyriba calls DPXCustom setup, non-Marketplace deployments

Both modes accept ISO 20022 pain.001, return pacs.002, and include full FATF R16 / MiCA / GENIUS Act compliance attestation.

Base URL: https://integration.untitledfinancial.com


DPX implements the Kyriba Payment Initiation Service SPI v1.0.0 — the certified connector contract from the Kyriba Connect Marketplace. Kyriba acts as the client; DPX acts as the server.

Base path: /bank-connectivity/payment-initiation/v1

Kyriba payment run
│ Kyriba-Context JWT (tenant identity)
│ Encrypted pain.001 payload (AES-256-GCM)
POST /bank-connectivity/payment-initiation/v1/bank/dpx-settlement-rail/payments
├── JWT verification (Kyriba-Context header)
├── Payload decryption (AES-256-GCM)
├── pain.001 parse (XML or JSON)
├── VoP → Compliance Oracle
├── FX rate → Stability Oracle
└── Settle → DPX rail (USDC on Base)
201 { "id": "dpx-payment-uuid" }
│ Kyriba polls for status
GET /bank-connectivity/payment-initiation/v1/bank/dpx-settlement-rail/payments/{id}/status
202 { status: { format: "pacs.002.001.10", payload: { ... } } }

Kyriba discovery — returns DPX’s identity as a registered payment service provider. No authentication required.

Terminal window
curl https://integration.untitledfinancial.com/bank-connectivity/payment-initiation/v1/banks
{
"metadata": { "total": 1, "count": 1, "limit": 100, "offset": 0 },
"results": [{
"id": "dpx-settlement-rail",
"name": "dpx-settlement-rail",
"title": "DPX Settlement Rail — Untitled_ LuxPerpetua Technologies, Inc."
}]
}

Submit a payment initiation. bankNameOrId must be dpx-settlement-rail.

Required headers:

HeaderDescription
Kyriba-ContextJWT identifying the Kyriba tenant (see Authentication)
Idempotency-KeyUnique per-payment key — duplicate submissions return the original payment ID
Content-Typeapplication/json

Request body:

{
"remittance": {
"format": "pain.001.001.09",
"subFormat": "XML",
"payload": {
"encryption": {
"algorithm": "AES-256-GCM",
"keyName": "dpx-default",
"initialVector": "<base64-encoded 12-byte IV>"
},
"body": {
"content": "<base64-encoded encrypted pain.001>",
"contentEncoding": "base64"
}
}
}
}

Sandbox mode (no KYRIBA_ENCRYPTION_KEY set): pass an unencrypted base64 pain.001 with no encryption block.

Response 201:

{ "id": "93e89fe0-a29f-40a5-b204-57d3dffc8812" }

GET /bank/{bankNameOrId}/payments/{paymentId}/status

Section titled “GET /bank/{bankNameOrId}/payments/{paymentId}/status”

Poll for payment status. Returns a pacs.002 in the Kyriba SPI envelope.

Required headers: Kyriba-Context JWT

Response 202:

{
"status": {
"format": "pacs.002.001.10",
"payload": {
"body": {
"content": "<base64-encoded pacs.002>",
"contentEncoding": "base64"
}
}
}
}

In production (with KYRIBA_ENCRYPTION_KEY set), the payload is AES-256-GCM encrypted. In sandbox, it is plain base64.

Decode the content to get the full pacs.002:

{
"Document": {
"FIToFIPmtStsRpt": {
"GrpHdr": { "MsgId": "DPX-93E89FE0", "CreDtTm": "2026-05-15T..." },
"TxInfAndSts": [{
"OrgnlEndToEndId": "KYRIBA-REF-001",
"TxSts": "ACCP",
"SplmtryData": [{
"Envlp": {
"connector": "dpx-settlement-rail",
"DPXPaymentId": "93e89fe0-...",
"network": "base-mainnet",
"settlementAsset": "USDC",
"txHash": "0x...",
"fatfR16Compliant": true,
"micaCompliant": true
}
}]
}]
}
}
}

pacs.002 status codes:

TxStsMeaning
ACCPSettled — txHash present
PDNGIn progress
RJCTBlocked — rejectReason present

The Kyriba-Context header is a JWT signed by Kyriba identifying the tenant. DPX verifies:

  • JWT structure (3 parts)
  • Expiry (exp claim)
  • HMAC-SHA256 signature against KYRIBA_JWT_SECRET (production only; structure-only in sandbox)

JWT claims:

ClaimDescription
isshttps://<tenant>.treasury-factory.com/gateway
sub<clientId>@<tenantId>
auddpx-settlement-rail
kidKey name used for signing
expExpiry timestamp
jtiUnique token identifier (32 hex chars)
payload_hashSHA-256 of the unencrypted pain.001

Production deployments use AES-256-GCM to encrypt the pain.001 payload before transmission. The shared key (KYRIBA_ENCRYPTION_KEY) is a 64-character hex string (32 bytes) exchanged during Kyriba connector certification.

Kyriba DPX
│ │
│ AES-256-GCM encrypt(pain.001, key) │
│ ──────────────────────────────────── ▶ │
│ │ AES-256-GCM decrypt(body.content, key)
│ │ → plain pain.001 XML / JSON
│ │ → processPayment()
│ │
│ AES-256-GCM decrypt(pacs.002 body) │
│ ◀ ────────────────────────────────── │
│ │ AES-256-GCM encrypt(pacs.002, key)

Secrets to configure (via wrangler secret put):

SecretDescription
KYRIBA_JWT_SECRETHMAC-SHA256 key — provided by Kyriba during certification
KYRIBA_ENCRYPTION_KEY64-char hex AES-256 key — generate: openssl rand -hex 32

The Idempotency-Key header deduplicates submissions. If Kyriba retries a payment with the same key, DPX returns the original payment ID without reprocessing:

First call: Idempotency-Key: KYRIBA-REF-001 → 201 { "id": "abc123" }
Retry: Idempotency-Key: KYRIBA-REF-001 → 201 { "id": "abc123" } (no duplicate)

Test the full SPI flow without production credentials:

Terminal window
# 1. Build a mock JWT (structure only — no secret required in sandbox)
HEADER=$(echo -n '{"alg":"HS256","typ":"JWT"}' | base64 | tr -d '=' | tr '+/' '-_')
PAYLOAD=$(echo -n '{
"iss":"https://sandbox.treasury-factory.com/gateway",
"sub":"test@sandbox",
"aud":"dpx-settlement-rail",
"kid":"sandbox-key-1",
"exp":'$(($(date +%s)+3600))',
"iat":'$(date +%s)',
"jti":"aabbccddeeff00112233445566778899",
"payload_hash":"abc123"
}' | base64 | tr -d '=' | tr '+/' '-_')
JWT="$HEADER.$PAYLOAD.sandbox-sig"
# 2. Base64-encode a pain.001 XML (unencrypted sandbox payload)
PAIN=$(base64 < pain001.xml)
# 3. Submit
curl -X POST \
https://integration.untitledfinancial.com/bank-connectivity/payment-initiation/v1/bank/dpx-settlement-rail/payments \
-H "Content-Type: application/json" \
-H "Kyriba-Context: $JWT" \
-H "Idempotency-Key: SANDBOX-$(date +%s)" \
-d '{
"remittance": {
"format": "pain.001.001.09",
"subFormat": "XML",
"payload": {
"body": { "content": "'$PAIN'", "contentEncoding": "base64" }
}
}
}'

For non-Marketplace or custom deployments, Kyriba can push pain.001 directly to the DPX Integration API using a bearer token.

Kyriba payment run
│ ISO 20022 pain.001 (JSON or XML)
│ Authorization: Bearer <institution-key>
POST https://integration.untitledfinancial.com/payments/initiate
├── VoP check → Compliance Oracle
├── FX rate → Stability Oracle
└── Settle → DPX rail (USDC on Base)
pacs.002 response + webhook callback to Kyriba

Contact DPX to receive your institution bearer token.

In Kyriba, navigate to Administration → Payment Types → New:

FieldValue
NameDPX Settlement
MethodHTTP Request (REST)
URLhttps://integration.untitledfinancial.com/payments/initiate
Auth typeBearer token
Token<your-institution-key>
Content-Typeapplication/json
Kyriba outputIntegration API field
Transaction referencetmsReference
Instructed amountamount
Currencycurrency
Beneficiary namecreditor.name
Beneficiary LEIcreditor.lei
Beneficiary wallet / accountcreditor.walletAddress
Ordering customer LEIdebtor.lei
Remittance informationremittanceInfo
Requested execution daterequestedExecutionDate
Kyriba callback URLcallbackUrl
Terminal window
curl -X POST https://integration.untitledfinancial.com/payments/initiate \
-H "Authorization: Bearer <key>" \
-H "Content-Type: application/json" \
-d '{
"tmsReference": "KYRIBA-2026-0042",
"amount": "250000.00",
"currency": "USD",
"settlementAsset": "USDC",
"creditor": {
"name": "Acme Global Corp",
"lei": "5493001KJTIIGC8Y1R12",
"walletAddress": "0x742d35Cc6634C0532925a3b8D4C9Db96590c32E8"
},
"debtor": {
"name": "Ordering Corp",
"lei": "213800WSGIIZCXF1P572",
"walletAddress": "0x1234567890123456789012345678901234567890"
},
"remittanceInfo": "Invoice INV-2026-0042",
"callbackUrl": "https://your-kyriba-instance/dpx/callback"
}'

Set callbackUrl to your Kyriba inbound endpoint. DPX POSTs the full settlement result there on completion, signed with X-DPX-Signature (HMAC-SHA256).

See Webhook Events for the full payload schema.

The Integration API also accepts raw pain.001 JSON directly:

Terminal window
curl -X POST https://integration.untitledfinancial.com/payments/initiate \
-H "Authorization: Bearer <key>" \
-H "Content-Type: application/json" \
-d '{
"Document": {
"CstmrCdtTrfInitn": { "..." }
}
}'

Every DPX settlement — via SPI or direct — includes a full compliance block:

"compliance": {
"fatfR16Compliant": true,
"micaCompliant": true,
"geniusCompliant": true,
"regulatoryNote": "FATF R16 VoP satisfied — settlement compliant."
}

FinCEN Travel Rule records (IVMS 101) are automatically generated for all payments ≥ $3,000 and stored for 5 years. See FinCEN Travel Rule.