Skip to main content
This guide walks through a cross-platform DvP where Platform A’s seller delivers tokens to Platform B’s buyer.

Flow overview

Step 1: Platform A initiates

Platform A creates the settlement with their own seller’s details inline, and specifies Platform B as the counterparty:
curl -X POST https://api.keystoneos.xyz/v1/settlements \
  -H "Authorization: Bearer $PLATFORM_A_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "idempotency_key": "cross-dvp-001",
    "template_id": "CROSS_PLATFORM_DvP_TEMPLATE",
    "timeout_at": "2026-03-17T12:00:00Z",
    "parties": [
      {
        "role": "seller",
        "external_reference": "seller-001",
        "name": "Acme Securities",
        "wallet_address": "0xSellerWallet...",
        "chain_id": 11155111
      }
    ],
    "counterparty_parties": [
      {
        "platform_slug": "platform-b",
        "role": "buyer",
        "wallet_address_hint": "0xBuyerHint...",
        "counterparty_reference": "Acme Fund LLC"
      }
    ],
    "legs": [
      {
        "leg_type": "asset",
        "instrument_id": "0xTokenAddress",
        "quantity": "500",
        "direction": "deliver",
        "party_role": "seller"
      },
      {
        "leg_type": "payment",
        "instrument_id": "USDC",
        "quantity": "125000",
        "direction": "deliver",
        "party_role": "buyer"
      }
    ]
  }'
The settlement is created with settlement_type: "cross_platform" and the engine pauses at AWAITING_CONFIRMATION.

Step 2: Platform B receives notification

Platform B’s webhook endpoint receives:
{
  "event": "settlement.confirmation_required",
  "data": {
    "settlement_id": "stl-...",
    "role": "buyer",
    "wallet_address_hint": "0xBuyerHint...",
    "counterparty_reference": "Acme Fund LLC",
    "legs": [...]
  }
}
Platform B uses the hints to identify which entity should be assigned to this settlement.

Step 3: Platform B confirms

Platform B provides the actual party details for their side of the settlement:
curl -X POST https://api.keystoneos.xyz/v1/settlements/$SETTLEMENT_ID/confirm \
  -H "Authorization: Bearer $PLATFORM_B_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "external_reference": "buyer-acct-042",
    "name": "Beta Capital",
    "wallet_address": "0xBuyerWallet...",
    "chain_id": 11155111
  }'
Platform B authenticates with its own M2M token. KeyStone verifies that Platform B has a pending party in this settlement.

Step 4: Settlement proceeds

Once all parties are confirmed, the engine resumes and processes the settlement through the normal flow: compliance, escrow registration, deposit monitoring, execution, and finalization. Both platforms receive webhooks at every state transition.

Rejecting a settlement

If Platform B doesn’t want to participate:
curl -X POST https://api.keystoneos.xyz/v1/settlements/$SETTLEMENT_ID/reject \
  -H "Authorization: Bearer $PLATFORM_B_TOKEN" \
  -d '{"reason": "Entity not eligible"}'
The settlement transitions to a failure state. Platform A is notified via webhook.

Hints are optional

The wallet_address_hint and counterparty_reference fields in counterparty_parties are optional. They’re useful when:
  • Same user across platforms - provide the wallet address hint
  • Pre-agreed OTC trade - provide the entity name or LEI
  • Unknown counterparty - omit both, Platform B assigns whoever they want
Platform B always has final say via the confirmation call.

Template differences

Cross-platform templates include an await_confirmation action that single-platform templates skip:
{
  "INSTRUCTED": {
    "type": "await_confirmation",
    "provider": "internal",
    "resolution": "manual"
  }
}
This causes the engine to pause until all counterparties confirm (or one rejects).