> ## 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.

# Quickstart

> Get your first settlement running in under 10 minutes.

This guide walks you through a complete DvP (Delivery vs. Payment) settlement using bilateral instruction submission and autonomous on-chain execution.

## Prerequisites

* A KeyStone OS platform account with API credentials (M2M client ID and secret) - find these in the [KeyStone Dashboard](https://app.keystoneos.xyz) under **Settings > General**
* An active environment (sandbox or production)

## Step 1: Authenticate

KeyStone uses Auth0 M2M (client credentials) tokens for platform API access.

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://auth.keystoneos.xyz/oauth/token \
    --header 'content-type: application/json' \
    --data '{
      "client_id": "YOUR_CLIENT_ID",
      "client_secret": "YOUR_CLIENT_SECRET",
      "audience": "https://api.keystoneos.xyz",
      "grant_type": "client_credentials"
    }'
  ```

  ```typescript TypeScript SDK theme={null}
  import { KeystoneClient } from "@keystoneos/sdk";

  // The SDK handles token acquisition and refresh automatically
  const client = new KeystoneClient({
    clientId: "YOUR_CLIENT_ID",
    clientSecret: "YOUR_CLIENT_SECRET",
  });
  ```

  ```python Python SDK theme={null}
  from keystoneos import KeystoneClient

  # The SDK handles token acquisition and refresh automatically
  client = KeystoneClient(
      client_id="YOUR_CLIENT_ID",
      client_secret="YOUR_CLIENT_SECRET",
  )
  ```
</CodeGroup>

The returned `access_token` is a JWT valid for 24 hours. Include it in all API requests:

```
Authorization: Bearer {access_token}
```

## Step 2: Browse available templates

Templates define the settlement workflow and are pre-configured by KeyStone. Browse the available templates to find the right one for your use case.

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.keystoneos.xyz/v1/settlement-templates \
    -H "Authorization: Bearer $TOKEN"
  ```

  ```typescript TypeScript SDK theme={null}
  const { items } = await client.templates.list();

  for (const template of items) {
    console.log(`${template.slug} - ${template.name}`);
  }
  ```

  ```python Python SDK theme={null}
  result = await client.templates.list()

  for template in result.items:
      print(f"{template.slug} - {template.name}")
  ```
</CodeGroup>

Pick the template that matches your settlement type. For a standard DvP settlement, use the `dvp-standard` template. Note the `slug` field - you will reference it when submitting instructions.

## Step 3: Submit the seller instruction

Submit one side of the trade. KeyStone generates a trade reference that your counterparty will use to submit the other side.

<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-2026-001",
      "template_slug": "dvp-standard",
      "role": "seller",
      "party": {
        "external_reference": "seller-001",
        "name": "Acme Securities",
        "wallet_address": "0xSellerWallet..."
      },
      "legs": [
        {
          "leg_type": "asset_delivery",
          "instrument_id": "0xTokenContractAddress",
          "quantity": "100",
          "direction": "deliver",
          "chain_id": 11155111
        },
        {
          "leg_type": "payment",
          "instrument_id": "0xUSDCAddress",
          "quantity": "50000",
          "direction": "receive",
          "chain_id": 11155111
        }
      ],
      "timeout_at": "2026-03-20T00:00:00Z"
    }'
  ```

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

  console.log(instruction.tradeReference); // "KS-a1b2c3d4-..."
  ```

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

  print(instruction.trade_reference)  # "KS-a1b2c3d4-..."
  ```
</CodeGroup>

The response includes a generated trade reference:

```json theme={null}
{
  "id": "inst-...",
  "trade_reference": "KS-a1b2c3d4-...",
  "status": "pending_match",
  "settlement_id": null
}
```

## Step 4: Share trade reference with counterparty

Send the `trade_reference` to your counterparty through your own channels (email, chat, API integration, etc.). They will use it to submit the matching instruction.

## Step 5: Counterparty submits matching instruction

The counterparty submits their side with the same trade reference:

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

  ```typescript TypeScript SDK theme={null}
  const buyerInstruction = await counterpartyClient.instructions.submit({
    idempotencyKey: counterpartyClient.generateIdempotencyKey(),
    tradeReference: "KS-a1b2c3d4-...",
    templateSlug: "dvp-standard",
    role: "buyer",
    party: {
      externalReference: "buyer-001",
      name: "Beta Capital",
      walletAddress: "0xBuyerWallet...",
    },
    legs: [
      { legType: "asset_delivery", instrumentId: "0xTokenContractAddress", quantity: "100", direction: "receive", chainId: 11155111 },
      { legType: "payment", instrumentId: "0xUSDCAddress", quantity: "50000", direction: "deliver", chainId: 11155111 },
    ],
    timeoutAt: "2026-03-20T00:00:00Z",
  });

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

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

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

When the instructions match, the response includes the new settlement:

```json theme={null}
{
  "id": "inst-...",
  "trade_reference": "KS-a1b2c3d4-...",
  "status": "matched",
  "settlement_id": "550e8400-..."
}
```

## Step 6: Settlement created on-chain

After matching, the settlement enters `INSTRUCTED` and KeyStone registers it on the KeystoneSettlement contract - recipients, deposit keys, party hashes, and the timeout are all bound at registration.

## Step 7: Compliance runs automatically

If the template has compliance configured, KeyStone screens all parties through LSEG World-Check (entity) and CipherOwl (wallet), then attests the results to the ComplianceRegistry on-chain. The contract enforces that compliance must pass before the settlement can advance.

## Step 8: Both parties deposit to escrow

When the settlement reaches `AWAITING_DEPOSITS`, the settlement response includes a `deposit_secret` and `deposit_key` for each leg. Both parties deposit their assets directly to the escrow smart contract by calling `depositLeg(settlementId, legIndex, depositSecret)`. Your platform uses its custody provider to sign the deposit transaction. KeyStone is not involved in the deposit step.

## Step 9: Contracts auto-execute and finalize

The last deposit executes the settlement inline once the compliance gate passes - the contract pays every leg to its recipient bound at registration in one atomic transaction. Tokens go to the buyer, USDC goes to the seller. KeyStone observes the `SettlementExecuted` event and the settlement moves through `SETTLED` to `FINALIZED`.

## Step 10: Check the result

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

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

  ```python Python SDK theme={null}
  settlement = await client.settlements.get("550e8400-...")
  print(settlement.state)  # "FINALIZED"
  ```
</CodeGroup>

Or subscribe to webhooks for real-time notifications. Register a webhook endpoint in the [KeyStone Dashboard](https://app.keystoneos.xyz) under **Settings > Webhooks**.

## What happened

```
INSTRUCTED --> COMPLIANCE_CHECKING --> COMPLIANCE_CLEARED
           --> AWAITING_DEPOSITS --> SETTLED --> FINALIZED
```

| Phase                  | Who drives it                            |
| ---------------------- | ---------------------------------------- |
| Instruction matching   | KeyStone API (off-chain)                 |
| On-chain creation      | KeyStone engine                          |
| Compliance screening   | KeyStone compliance oracle               |
| Compliance attestation | KeyStone compliance oracle               |
| Past compliance gate   | KeyStone engine (one transition)         |
| Deposits               | Parties deposit directly to escrow       |
| Execution              | Contracts (autonomous)                   |
| Finalization           | Contracts (autonomous)                   |
| Timeout (if needed)    | Operator or any depositor (not pausable) |

<Card title="Next: Authentication" icon="arrow-right" href="/getting-started/authentication">
  Learn about M2M tokens, user tokens, scopes, and environment resolution.
</Card>
