The Inner-Workings of Our Settlement

9-state settlement engine lifecycle - from intent submission through finality proof, covering fiat-to-fiat, fiat-to-crypto, and crypto-to-crypto settlement lanes.

received validated compliance_check accepted ready submitted confirmed final | rejected failed cancelled expired
Color Legend
Client / Terminal
Settlement API
Compliance API
Ledger / L1
Finality Prover
Terminal Failure

01Settlement Types

The settlement engine supports three distinct lanes, each with different compliance paths and attestation requirements.

Fiat-to-Fiat (FI-to-FI)

Traditional cross-border bank settlement - complements existing SWIFT/DTCC rails with atomic finality.

Type: SIMPLE
Compliance: Single check (KYC/AML/sanctions)
Attestation: Auto-transition from accepted to ready
Travel Rule: FATF Wire Transfer Rule evaluation required
Party Data: Legal name, account ID, country, address
Example: Bank A (USD) → Bank B (EUR)
Fees: 35-90 bps per event, $1 floor (vs 50-100 bps SWIFT)

Fiat-to-Crypto (FI-to-Crypto)

On-ramp settlement for institutional crypto acquisition.

Type: SIMPLE or DVP
Compliance: Per-leg for DVP, single for SIMPLE
Attestation: DVP requires leg attestation per counterparty
Travel Rule: Applies to fiat leg
DVP Example: Fiat delivery (leg 1) vs crypto delivery (leg 2)
Example: Fund deposits USD → receives JIL/BTC/ETH

Crypto-to-Crypto

Cross-chain or same-chain token swaps with atomic execution.

Type: DVP or PVP
Compliance: Per-leg compliance, per-leg attestation
Attestation: Both legs must attest ready via POST /:id/attest-ready
PVP: Concurrent asset exchange (both legs atomic)
Example: Swap wBTC-JIL → wETH-JIL atomically
Finality: Both legs marked "settled" at FINAL

02Settlement State Machine - Happy Path

The 8-step happy path from client submission through finality. Each state transition is driven by the settlement engine's poll loop running at ENGINE_POLL_INTERVAL_MS (default 2000ms).

1
RECEIVED - Client Submits Settlement Intent
Client submits a settlement request via POST /v1/settlements. The engine creates a settlement record with a UUID and assigns a UETR (Unique End-to-End Transaction Reference). An expiry timer is set (default 60 minutes via SETTLEMENT_EXPIRY_MINUTES). Travel rule evaluation runs immediately - if the settlement involves fiat legs, FATF Wire Transfer Rule checks are applied to validate party data (legal name, account identifier, country, address).

If travel rule fails → REJECTED. If passes → VALIDATED.
Client SDK settlement-api :8050
travel rule passed
2
VALIDATED - Schema Verified, Compliance Initiated
Schema validation complete and travel rule passed. The settlement engine now initiates compliance checks. For SIMPLE settlements, a single compliance check covers the entire settlement (KYC, AML, sanctions screening). For DVP / PVP settlements, each leg triggers an independent compliance check. The compliance request is dispatched to compliance-api :8100 with zone-specific screening parameters.
settlement-api :8050 compliance-api :8100
compliance request dispatched
3
COMPLIANCE_CHECK - ZK Compliance Proofs Generated
The compliance API generates zero-knowledge compliance proofs for each required check. KYC verification, AML screening, and sanctions list evaluation run per compliance zone. A compliance receipt hash is computed and stored for auditability.

For DVP/PVP: each leg is independently evaluated. Compliance is atomic - if any leg is denied, the entire settlement is rejected (one leg fails = whole settlement fails).

If any leg denied → REJECTED. If all pass (decision = "allow") → ACCEPTED.
compliance-api :8100 proof-verifier :8250
decision = "allow"
4
ACCEPTED - Compliance Verified, Awaiting Readiness
Compliance checks have passed. What happens next depends on the settlement type:

SIMPLE: Auto-transition to READY immediately. No manual attestation needed - the engine moves the settlement forward on the next poll tick.

DVP/PVP: The settlement enters a waiting state. Each counterparty must confirm their leg via POST /v1/settlements/:id/attest-ready. The engine holds at ACCEPTED until all legs are attested. Once every leg has been attested → READY.
settlement-api :8050 settlement-consumer :8051
all legs attested (or auto for SIMPLE)
5
READY - All Preconditions Met, Submitting to L1
All preconditions are satisfied. The settlement engine submits the transaction to JIL L1 via the ledger-router :8000. An L1 tx_id is assigned upon successful submission.

For DVP/PVP settlements, the primary leg is used for L1 submission. The ledger-router coordinates multi-leg atomic execution on the L1 engine.

If L1 submission fails → FAILED. If succeeds → SUBMITTED.
ledger-router :8000 ledger-service :8001
tx_id assigned, included in mempool
6
SUBMITTED - Transaction Included in Block
The transaction has been included in a JIL L1 block. The engine records the block height (block_height) and block hash (block_hash). A confirmation counter begins tracking subsequent blocks.

A submission timeout is enforced - if the transaction is not confirmed within the timeout window, the settlement transitions to FAILED.

If timeout → FAILED. If block inclusion confirmed → CONFIRMED.
jil5600-core (Rust L1) settlement-consumer :8051
block confirmed, tracking confirmations
7
CONFIRMED - Accumulating Confirmations
The block containing this settlement has been included in the chain. Confirmations accumulate with each new block produced after the settlement's block. The finality threshold is FINALITY_CONFIRMATIONS=6 (default).

The engine re-checks the confirmation count on each poll tick (ENGINE_POLL_INTERVAL_MS). Once the threshold is met → FINAL.
finality-prover settlement-consumer :8051
6 confirmations reached
8
FINAL - Settlement Complete
Finality threshold met. The settlement engine performs the following final operations:

1. Fee calculated at finality (SETTLEMENT_FEE_BPS=35, i.e. 35-90 bps per event, $1 floor).
2. Settlement receipt assembled with all proofs and metadata.
3. Finality proof stored in the proof store.
4. For DVP/PVP: all legs marked as "settled".
5. Webhook dispatched to the client's registered callback URL.
6. Kafka event published: SETTLEMENT_FINAL.
7. Batch settlement counts updated.
settlement-api :8050 settlement-consumer :8051 proof-verifier :8250

03DVP/PVP Leg Attestation Flow

For multi-leg settlements (DVP and PVP), the engine holds at the ACCEPTED state until all counterparties have confirmed their legs. This section details the attestation branching.

A
ACCEPTED - DVP/PVP Waiting for Attestations
Settlement is compliance-approved. The engine creates attestation slots for each leg.
// DVP example: 2 legs
leg_1: { party: "counterparty_a", attested: false, asset: "USD" }
leg_2: { party: "counterparty_b", attested: false, asset: "wBTC-JIL" }
settlement-api :8050
counterparty_a calls attest-ready
B
Leg 1 Attested - Waiting for Leg 2
Counterparty A has confirmed their leg. The engine updates the attestation record. Settlement remains at ACCEPTED because not all legs are attested yet.
POST /v1/settlements/{id}/attest-ready
{ "leg_id": "leg_1", "party_id": "counterparty_a" }
settlement-api :8050
counterparty_b calls attest-ready
C
All Legs Attested - Transition to READY
Both counterparties have attested their legs. On the next engine poll tick, the settlement transitions from ACCEPTED to READY and proceeds to L1 submission.

For PVP: both legs are bundled into a single atomic L1 transaction. For DVP: the primary leg is submitted first, with the secondary leg following once the primary is confirmed.
settlement-api :8050 ledger-router :8000

04Terminal Failure States

Settlements can exit the happy path and reach a terminal failure state at several points in the lifecycle.

×
REJECTED - Travel Rule or Compliance Failure
The settlement has been permanently rejected due to a compliance failure. This is a terminal state - no recovery is possible.

Causes:
• Travel rule evaluation failed (missing or invalid party data)
• KYC check failed (unverified counterparty)
• AML screening flagged (suspicious activity pattern)
• Sanctions list match (OFAC, EU, UN)
• Any single leg denied in a DVP/PVP settlement (atomic rejection)

Can occur from: RECEIVED, VALIDATED, COMPLIANCE_CHECK
compliance-api :8100 settlement-api :8050
terminal - no recovery
×
FAILED - L1 Submission or Confirmation Failure
The settlement failed during the execution phase. This is a terminal state.

Causes:
• L1 transaction submission rejected by ledger-router (insufficient balance, invalid tx)
• L1 submission timeout (transaction not included in a block within the window)
• Block confirmation timeout (transaction included but chain stalled)
• L1 engine internal error (jil5600-core error)

Can occur from: READY, SUBMITTED
ledger-router :8000 jil5600-core
terminal - no recovery
×
CANCELLED - Client-Initiated Cancellation
The client has explicitly cancelled the settlement via POST /v1/settlements/:id/cancel. Cancellation is only permitted while the settlement is in a pre-execution state.

Cancellable states: RECEIVED, VALIDATED, ACCEPTED, READY
Non-cancellable states: SUBMITTED, CONFIRMED, FINAL (already on-chain)
Client SDK settlement-api :8050
terminal - client choice
×
EXPIRED - Deadline Exceeded
The settlement has exceeded its expiry deadline (default: SETTLEMENT_EXPIRY_MINUTES=60). The engine checks expiry on each poll tick and automatically transitions stale settlements to EXPIRED.

Common causes:
• DVP/PVP settlement where one counterparty never attested their leg
• Compliance check took too long (external provider timeout)
• Client submitted but never completed follow-up actions

Can occur from: RECEIVED, VALIDATED, COMPLIANCE_CHECK, ACCEPTED
settlement-consumer :8051

05API Endpoints

Method Endpoint Purpose Notes
POST /v1/settlements Create a new settlement Returns settlement UUID and UETR. Body includes type (SIMPLE/DVP/PVP), parties, amount, asset, legs.
POST /v1/settlements/batch Batch create settlements 1-100 SIMPLE settlements per batch. Returns array of UUIDs. DVP/PVP not supported in batch.
POST /v1/settlements/:id/cancel Cancel a settlement Only valid in states: received, validated, accepted, ready. Returns 409 if already submitted.
POST /v1/settlements/:id/attest-ready DVP/PVP leg attestation Counterparty confirms their leg is ready. Body: { leg_id, party_id }. Idempotent.
GET /v1/settlements/:id Get settlement status Returns full settlement record including current state, legs, compliance receipt, timestamps.
GET /v1/settlements/:id/proof Get finality proof Only available when state = FINAL. Returns ZK compliance proof + L1 finality proof.
GET /v1/settlements/:id/receipt Get settlement receipt Only available when state = FINAL. Returns full receipt with fee, block height, finality data.

Example: Create a SIMPLE Settlement

POST /v1/settlements
{
  "type": "SIMPLE",
  "asset": "USD",
  "amount": "1000000.00",
  "sender": {
    "legal_name": "Acme Bank NA",
    "account_id": "acct_sender_001",
    "country": "US",
    "address": "123 Wall St, New York, NY 10005"
  },
  "receiver": {
    "legal_name": "Deutsche Finanz AG",
    "account_id": "acct_receiver_002",
    "country": "DE",
    "address": "Taunusanlage 12, 60325 Frankfurt"
  },
  "callback_url": "https://api.acmebank.com/webhooks/settlement"
}

Example: Create a DVP Settlement

POST /v1/settlements
{
  "type": "DVP",
  "legs": [
    {
      "leg_id": "leg_1",
      "direction": "delivery",
      "asset": "USD",
      "amount": "50000.00",
      "party": { "party_id": "counterparty_a", "legal_name": "Fund Alpha LP" }
    },
    {
      "leg_id": "leg_2",
      "direction": "payment",
      "asset": "wBTC-JIL",
      "amount": "0.75000000",
      "party": { "party_id": "counterparty_b", "legal_name": "OTC Desk Corp" }
    }
  ],
  "callback_url": "https://api.fundalpha.com/webhooks/settlement"
}

06Service Architecture

The settlement lifecycle is orchestrated across five services, each responsible for specific state transitions.

Service Port Responsibility States Handled
settlement-api :8050 HTTP API, settlement creation, cancellation, attestation, receipt assembly, webhook dispatch All states (orchestration layer)
settlement-consumer :8051 Kafka consumer, engine poll loop, state transition executor, expiry checker, batch counter All state transitions (engine driver)
compliance-api :8100 ZK compliance proof generation, KYC/AML/sanctions screening, travel rule evaluation VALIDATED → COMPLIANCE_CHECK → ACCEPTED or REJECTED
ledger-router :8000 L1 transaction routing, submission to jil5600-core, block confirmation tracking READY → SUBMITTED → CONFIRMED
jil5600-core Rust L1 Block production, transaction execution, consensus, finality determination SUBMITTED → CONFIRMED → FINAL (block-level)

07Database Schema

settlements

id                     UUID PRIMARY KEY
uetr                   UUID NOT NULL UNIQUE       -- Unique End-to-End Transaction Reference
type                   TEXT NOT NULL               -- SIMPLE | DVP | PVP
status                 TEXT NOT NULL               -- received | validated | compliance_check | accepted | ready | submitted | confirmed | final | rejected | failed | cancelled | expired
asset                  TEXT NOT NULL               -- primary settlement asset
amount                 NUMERIC NOT NULL
sender_legal_name      TEXT
sender_account_id      TEXT NOT NULL
sender_country         TEXT
sender_address         TEXT
receiver_legal_name    TEXT
receiver_account_id    TEXT NOT NULL
receiver_country       TEXT
receiver_address       TEXT
compliance_receipt     TEXT                       -- SHA-256 of compliance proof bundle
compliance_decision    TEXT                       -- allow | deny
travel_rule_result     TEXT                       -- pass | fail | not_applicable
tx_id                  TEXT                       -- L1 transaction ID (set at SUBMITTED)
block_height           BIGINT                     -- L1 block height (set at CONFIRMED)
block_hash             TEXT                       -- L1 block hash
confirmations          INT DEFAULT 0
fee_bps                INT                        -- fee in basis points (set at FINAL)
fee_amount             NUMERIC                    -- calculated fee amount
finality_proof         TEXT                       -- finality proof hash (set at FINAL)
callback_url           TEXT                       -- webhook URL for notifications
batch_id               UUID                       -- batch reference (if created via /batch)
expires_at             TIMESTAMPTZ NOT NULL       -- expiry deadline
created_at             TIMESTAMPTZ DEFAULT NOW()
updated_at             TIMESTAMPTZ DEFAULT NOW()
      

settlement_legs

id                     UUID PRIMARY KEY
settlement_id          UUID NOT NULL REFERENCES settlements(id)
leg_id                 TEXT NOT NULL               -- e.g. "leg_1", "leg_2"
direction              TEXT NOT NULL               -- delivery | payment
asset                  TEXT NOT NULL
amount                 NUMERIC NOT NULL
party_id               TEXT NOT NULL
party_legal_name       TEXT
compliance_receipt     TEXT                       -- per-leg compliance proof hash
compliance_decision    TEXT                       -- allow | deny
attested               BOOLEAN DEFAULT FALSE
attested_at            TIMESTAMPTZ
status                 TEXT DEFAULT 'pending'     -- pending | attested | settled | failed
created_at             TIMESTAMPTZ DEFAULT NOW()
      

settlement_events

id                     BIGSERIAL PRIMARY KEY
settlement_id          UUID NOT NULL REFERENCES settlements(id)
event_type             TEXT NOT NULL               -- state_change | compliance_result | leg_attested | webhook_sent | error
from_state             TEXT
to_state               TEXT
metadata               JSONB                      -- event-specific payload
created_at             TIMESTAMPTZ DEFAULT NOW()
      

08Configuration

Key configuration parameters for the settlement engine. All values are set via environment variables.

FINALITY_CONFIRMATIONS
6
Number of L1 block confirmations required before a settlement reaches FINAL state.
ENGINE_POLL_INTERVAL_MS
2000
Poll interval (ms) for the settlement engine tick loop. Each tick checks for pending state transitions and expiry.
SETTLEMENT_FEE_BPS
35
Settlement fee in basis points (0.35%). Applied at finality. Effective range: 35-90 bps per event, $1 floor.
SETTLEMENT_EXPIRY_MINUTES
60
Default expiry deadline (minutes) for new settlements. Settlements not finalized within this window are automatically expired.
Variable Service Default Purpose
FINALITY_CONFIRMATIONS settlement-consumer 6 L1 block confirmations for finality threshold
ENGINE_POLL_INTERVAL_MS settlement-consumer 2000 Engine tick loop interval in milliseconds
SETTLEMENT_FEE_BPS settlement-api 5 Fee basis points applied at finality
SETTLEMENT_EXPIRY_MINUTES settlement-api 60 Settlement expiry deadline in minutes
SETTLEMENT_BATCH_MAX settlement-api 100 Maximum settlements per batch request
COMPLIANCE_API_URL settlement-api http://compliance-api:8100 Compliance API base URL
LEDGER_ROUTER_URL settlement-api http://ledger-router:8000 Ledger router base URL for L1 submission
KAFKA_BROKERS settlement-consumer redpanda:9092 Kafka/RedPanda broker addresses
WEBHOOK_TIMEOUT_MS settlement-api 5000 Timeout for webhook delivery attempts
WEBHOOK_MAX_RETRIES settlement-api 3 Maximum webhook delivery retry attempts

09Key Source Files

File Purpose
services/settlement-api/src/index.ts Settlement API server - HTTP endpoints, create/cancel/attest-ready handlers
services/settlement-api/src/engine.ts Settlement state machine - state transition logic, expiry checks, fee calculation
services/settlement-api/src/compliance.ts Compliance integration - dispatches checks to compliance-api, processes results
services/settlement-api/src/travel-rule.ts Travel rule evaluation - FATF Wire Transfer Rule party data validation
services/settlement-consumer/src/index.ts Kafka consumer - engine poll loop, processes settlement.* topic events
services/compliance-api/src/index.ts Compliance API - ZK proof generation, KYC/AML/sanctions screening
services/ledger-router/src/index.ts Ledger router - L1 transaction submission, block confirmation tracking
services/settlement-api/migrations/001_settlements.sql Settlement tables schema - settlements, settlement_legs, settlement_events
docs/openapi/settlement-router.yaml OpenAPI specification for settlement API endpoints