> ## Documentation Index
> Fetch the complete documentation index at: https://docs.keystoneos.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Single-Platform DvP

> Step-by-step guide for a Delivery vs. Payment settlement within a single platform.

This guide walks through a complete single-platform DvP settlement where both buyer and seller are on your platform. After compliance, the contracts handle everything autonomously.

## Prerequisites

* Authenticated with M2M token ([Authentication](/getting-started/authentication))
* A DvP settlement template available (browse via `GET /v1/settlement-templates`)

## Flow overview

```mermaid theme={null}
%%{init: {'theme': 'base', 'themeVariables': {'actorBkg': '#1a3a35', 'actorBorder': '#2DD4A8', 'actorTextColor': '#e0f2ef', 'actorLineColor': '#2DD4A8', 'signalColor': '#2DD4A8', 'signalTextColor': '#e0f2ef', 'noteBkgColor': '#162e2a', 'noteTextColor': '#e0f2ef', 'noteBorderColor': '#1AAF8B', 'activationBkgColor': '#1a3a35', 'activationBorderColor': '#2DD4A8', 'labelBoxBkgColor': '#1a3a35', 'labelBoxBorderColor': '#2DD4A8', 'labelTextColor': '#e0f2ef', 'loopTextColor': '#2DD4A8'}}}%%
sequenceDiagram
    participant P as Your Platform
    participant K as KeyStone API
    participant SC as Contracts
    participant Seller as Seller Wallet
    participant Buyer as Buyer Wallet

    P->>K: POST /instructions (seller side)
    K-->>P: trade_reference: "KS-..."
    P->>K: POST /instructions (buyer side, same trade_reference)
    K->>K: Match instructions, create settlement on-chain
    K->>K: Compliance screening + attestation

    Note over SC: Contracts take over (autonomous)
    Seller->>SC: Deposit tokens to escrow
    Buyer->>SC: Deposit USDC to escrow
    SC->>SC: Auto-execute atomic swap
    SC->>SC: Auto-finalize

    K-->>P: Webhook: settlement.state.finalized
```

## Step 1: Submit the seller instruction

Provide the seller's party details and their legs:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.keystoneos.xyz/v1/instructions \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "idempotency_key": "dvp-seller-001",
      "template_slug": "dvp-standard",
      "role": "seller",
      "party": {
        "external_reference": "seller-acct-001",
        "name": "Acme Securities",
        "wallet_address": "0xSellerWallet..."
      },
      "legs": [
        {
          "leg_type": "asset_delivery",
          "instrument_id": "0xTokenContractAddress",
          "quantity": "1000",
          "direction": "deliver",
          "chain_id": 11155111
        },
        {
          "leg_type": "payment",
          "instrument_id": "0xUSDCAddress",
          "quantity": "250000",
          "direction": "receive",
          "chain_id": 11155111
        }
      ],
      "timeout_at": "2026-03-17T12:00:00Z"
    }'
  ```

  ```typescript TypeScript SDK theme={null}
  const sellerInstruction = await client.instructions.submit({
    idempotencyKey: client.generateIdempotencyKey(),
    templateSlug: "dvp-standard",
    role: "seller",
    party: {
      externalReference: "seller-acct-001",
      name: "Acme Securities",
      walletAddress: "0xSellerWallet...",
    },
    legs: [
      { legType: "asset_delivery", instrumentId: "0xTokenContractAddress", quantity: "1000", direction: "deliver", chainId: 11155111 },
      { legType: "payment", instrumentId: "0xUSDCAddress", quantity: "250000", direction: "receive", chainId: 11155111 },
    ],
    timeoutAt: "2026-03-17T12:00:00Z",
  });

  const tradeReference = sellerInstruction.tradeReference;
  ```

  ```python Python SDK theme={null}
  seller_instruction = await client.instructions.submit({
      "idempotency_key": "dvp-seller-001",
      "template_slug": "dvp-standard",
      "role": "seller",
      "party": {
          "external_reference": "seller-acct-001",
          "name": "Acme Securities",
          "wallet_address": "0xSellerWallet...",
      },
      "legs": [
          {"leg_type": "asset_delivery", "instrument_id": "0xTokenContractAddress", "quantity": "1000", "direction": "deliver", "chain_id": 11155111},
          {"leg_type": "payment", "instrument_id": "0xUSDCAddress", "quantity": "250000", "direction": "receive", "chain_id": 11155111},
      ],
      "timeout_at": "2026-03-17T12:00:00Z",
  })

  trade_reference = seller_instruction.trade_reference
  ```
</CodeGroup>

Save the returned `trade_reference` for the next step.

## Step 2: Submit the buyer instruction

Submit the buyer's matching instruction with the same trade reference:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.keystoneos.xyz/v1/instructions \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "idempotency_key": "dvp-buyer-001",
      "trade_reference": "KS-abc123...",
      "template_slug": "dvp-standard",
      "role": "buyer",
      "party": {
        "external_reference": "buyer-acct-002",
        "name": "Beta Capital",
        "wallet_address": "0xBuyerWallet..."
      },
      "legs": [
        {
          "leg_type": "asset_delivery",
          "instrument_id": "0xTokenContractAddress",
          "quantity": "1000",
          "direction": "receive",
          "chain_id": 11155111
        },
        {
          "leg_type": "payment",
          "instrument_id": "0xUSDCAddress",
          "quantity": "250000",
          "direction": "deliver",
          "chain_id": 11155111
        }
      ],
      "timeout_at": "2026-03-17T12:00:00Z"
    }'
  ```

  ```typescript TypeScript SDK theme={null}
  const buyerInstruction = await client.instructions.submit({
    idempotencyKey: client.generateIdempotencyKey(),
    tradeReference: "KS-abc123...",
    templateSlug: "dvp-standard",
    role: "buyer",
    party: {
      externalReference: "buyer-acct-002",
      name: "Beta Capital",
      walletAddress: "0xBuyerWallet...",
    },
    legs: [
      { legType: "asset_delivery", instrumentId: "0xTokenContractAddress", quantity: "1000", direction: "receive", chainId: 11155111 },
      { legType: "payment", instrumentId: "0xUSDCAddress", quantity: "250000", direction: "deliver", chainId: 11155111 },
    ],
    timeoutAt: "2026-03-17T12:00:00Z",
  });

  console.log(buyerInstruction.status);       // "matched"
  console.log(buyerInstruction.settlementId); // "550e8400-..."
  ```

  ```python Python SDK theme={null}
  buyer_instruction = await client.instructions.submit({
      "idempotency_key": "dvp-buyer-001",
      "trade_reference": "KS-abc123...",
      "template_slug": "dvp-standard",
      "role": "buyer",
      "party": {
          "external_reference": "buyer-acct-002",
          "name": "Beta Capital",
          "wallet_address": "0xBuyerWallet...",
      },
      "legs": [
          {"leg_type": "asset_delivery", "instrument_id": "0xTokenContractAddress", "quantity": "1000", "direction": "receive", "chain_id": 11155111},
          {"leg_type": "payment", "instrument_id": "0xUSDCAddress", "quantity": "250000", "direction": "deliver", "chain_id": 11155111},
      ],
      "timeout_at": "2026-03-17T12:00:00Z",
  })

  print(buyer_instruction.status)         # "matched"
  print(buyer_instruction.settlement_id)  # "550e8400-..."
  ```
</CodeGroup>

The response includes `status: "matched"` and a `settlement_id`. The settlement is created on-chain and the engine begins processing.

## Step 3: Compliance screening

The engine automatically screens all parties through LSEG World-Check (entity) and CipherOwl (wallet). Results are attested to the ComplianceRegistry on-chain. In \~95% of cases, this completes automatically and the settlement advances to `COMPLIANCE_CLEARED`.

If a party is flagged, the settlement pauses. Submit a compliance decision to continue:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.keystoneos.xyz/v1/settlements/$SETTLEMENT_ID/compliance-decision \
    -H "Authorization: Bearer $TOKEN" \
    -d '{"decision": "approve"}'
  ```

  ```typescript TypeScript SDK theme={null}
  const settlement = await client.compliance.approve("550e8400-...");
  ```

  ```python Python SDK theme={null}
  settlement = await client.compliance.approve("550e8400-...")
  ```
</CodeGroup>

## Step 4: Parties deposit to escrow

Once compliance clears, the settlement reaches `AWAITING_DEPOSITS`. Both parties deposit their assets directly to the escrow smart contract on-chain using their `deposit_secret` (included in the settlement response for each leg). Your platform calls `depositLeg(settlementId, legIndex, depositSecret)` via its custody provider (such as MPC wallets or any signing infrastructure).

KeyStone is not involved in the deposit step. The escrow contract verifies `keccak256(depositSecret) == depositKey` to authorize each deposit.

## Step 5: Contracts auto-execute and finalize

When all deposits are confirmed, the contracts take over autonomously:

1. The last deposit triggers execution inline once the compliance gate passes
2. The contract verifies the compliance gate and pays every leg to its recipient bound at registration
3. Tokens go to the buyer's wallet, USDC goes to the seller's wallet
4. Settlement transitions to `FINALIZED`
5. Your webhook endpoint receives `settlement.state.finalized`

## Monitoring

Track the settlement via polling or webhooks:

<CodeGroup>
  ```bash cURL theme={null}
  # Get current state
  curl https://api.keystoneos.xyz/v1/settlements/$SETTLEMENT_ID \
    -H "Authorization: Bearer $TOKEN"

  # Get full event history
  curl https://api.keystoneos.xyz/v1/settlements/$SETTLEMENT_ID/events \
    -H "Authorization: Bearer $TOKEN"
  ```

  ```typescript TypeScript SDK theme={null}
  // Get current state
  const settlement = await client.settlements.get("550e8400-...");
  console.log(settlement.state);

  // Get full event history
  const events = await client.settlements.events("550e8400-...");
  for (const event of events.items) {
    console.log(`${event.fromState} -> ${event.toState}`);
  }
  ```

  ```python Python SDK theme={null}
  # Get current state
  settlement = await client.settlements.get("550e8400-...")
  print(settlement.state)

  # Get full event history
  events = await client.settlements.events("550e8400-...")
  for event in events.items:
      print(f"{event.from_state} -> {event.to_state}")
  ```
</CodeGroup>

## Error scenarios

| Scenario             | Result                                                                               |
| -------------------- | ------------------------------------------------------------------------------------ |
| Compliance rejection | Settlement -> `REJECTED` (before any deposits)                                       |
| Deposit timeout      | Settlement -> `TIMED_OUT`, deposits reclaimable on-chain (operator or any depositor) |
| Execution failure    | Settlement -> `ROLLED_BACK`, deposits returned                                       |
