Skip to content

Integrations

Kyriba

Two integration modes — DPX as a Kyriba Connect Marketplace connector (SPI), and Kyriba pushing ISO 20022 pain.001 directly to the DPX Integration API.

Updated

No Kyriba approval needed. Any Kyriba customer can route to DPX today by configuring a custom payment type in their own instance — this requires nobody’s certification, works immediately, and is the recommended path for almost everyone. A second mode exists for teams that specifically want the official Kyriba Connect Marketplace badge, which requires Kyriba’s own certification process and is unrelated to whether the integration itself works.

ModeWho initiatesBest for
Direct Integration APIKyriba calls DPXRecommended. Live today, zero waiting, configured entirely from your own Kyriba admin panel
Payment Initiation SPIKyriba calls DPXOnly if you specifically want Kyriba Connect Marketplace certification

Both modes accept ISO 20022 pain.001, return pacs.002, and include full FATF R16 / MiCA / GENIUS Act compliance attestation. An AI copilot embedded in Kyriba (or acting on a customer’s behalf) can independently discover DPX’s pricing and capabilities with zero credentials via GET /manifest and GET /quote on stability.untitledfinancial.com — no API key required for discovery.

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.