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

# Execute a Tokenised Repo

> Step-by-step guide to executing a tokenised repo settlement using bilateral instructions

This guide walks through a complete tokenised repo lifecycle - from opening to maturity to closing - using bilateral instructions and autonomous on-chain execution.

## Prerequisites

* Authenticated with M2M token ([Authentication](/getting-started/authentication))
* A DvP settlement template available
* Both parties have wallet addresses on a supported chain
* You know the repo economics: tenor, rate, and haircut

## Flow overview

A repo consists of two linked settlements:

1. **Opening**: Both parties submit `repo_open` instructions that match to create the opening settlement
2. **Closing**: KeyStone auto-creates a `repo_close` settlement when maturity arrives

Both settlements follow the standard flow: instruction matching, compliance, deposits to escrow, autonomous execution.

## Step 1: Submit opening instructions

Both counterparties submit instructions with `trade_type: "repo_open"` and matching `repo_terms`. The first party receives a trade reference, the second party includes it to trigger matching.

**Seller submits first:**

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.keystoneos.xyz/v1/instructions \
    -H "Authorization: Bearer $SELLER_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "template_slug": "dvp-standard",
      "role": "seller",
      "party": {
        "external_reference": "bond-holder-001",
        "name": "Acme Fixed Income",
        "wallet_address": "0xSellerWallet...",
        "chain_id": 11155111
      },
      "legs": [
        {
          "leg_type": "asset_delivery",
          "instrument_id": "0xBondTokenAddress",
          "quantity": "1000",
          "direction": "deliver"
        },
        {
          "instrument_id": "0xUSDCAddress",
          "quantity": "950000",
          "direction": "receive"
        }
      ],
      "timeout_at": "2026-03-20T12:00:00Z",
      "idempotency_key": "repo-seller-001",
      "trade_type": "repo_open",
      "repo_terms": {
        "tenor_days": 30,
        "rate_bps": 500,
        "haircut_bps": 500,
        "margin_band_lower": "0.95",
        "margin_band_upper": "1.05"
      }
    }'
  ```

  ```typescript TypeScript SDK theme={null}
  const sellerInstruction = await sellerClient.instructions.submit({
    idempotencyKey: sellerClient.generateIdempotencyKey(),
    templateSlug: "dvp-standard",
    role: "seller",
    party: {
      externalReference: "bond-holder-001",
      name: "Acme Fixed Income",
      walletAddress: "0xSellerWallet...",
      chainId: 11155111,
    },
    legs: [
      { legType: "asset_delivery", instrumentId: "0xBondTokenAddress", quantity: "1000", direction: "deliver" },
      { instrumentId: "0xUSDCAddress", quantity: "950000", direction: "receive" },
    ],
    timeoutAt: "2026-03-20T12:00:00Z",
    tradeType: "repo_open",
    repoTerms: {
      tenorDays: 30,
      rateBps: 500,
      haircutBps: 500,
      marginBandLower: "0.95",
      marginBandUpper: "1.05",
    },
  });

  const tradeReference = sellerInstruction.tradeReference;
  ```

  ```python Python SDK theme={null}
  seller_instruction = await seller_client.instructions.submit({
      "template_slug": "dvp-standard",
      "role": "seller",
      "party": {
          "external_reference": "bond-holder-001",
          "name": "Acme Fixed Income",
          "wallet_address": "0xSellerWallet...",
          "chain_id": 11155111,
      },
      "legs": [
          {"leg_type": "asset_delivery", "instrument_id": "0xBondTokenAddress", "quantity": "1000", "direction": "deliver"},
          {"instrument_id": "0xUSDCAddress", "quantity": "950000", "direction": "receive"},
      ],
      "timeout_at": "2026-03-20T12:00:00Z",
      "idempotency_key": "repo-seller-001",
      "trade_type": "repo_open",
      "repo_terms": {
          "tenor_days": 30,
          "rate_bps": 500,
          "haircut_bps": 500,
          "margin_band_lower": "0.95",
          "margin_band_upper": "1.05",
      },
  })

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

**Response includes a `trade_reference`:**

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

**Buyer submits with the same `trade_reference`:**

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.keystoneos.xyz/v1/instructions \
    -H "Authorization: Bearer $BUYER_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "trade_reference": "KS-abc123...",
      "template_slug": "dvp-standard",
      "role": "buyer",
      "party": {
        "external_reference": "cash-lender-002",
        "name": "Beta Capital",
        "wallet_address": "0xBuyerWallet...",
        "chain_id": 11155111
      },
      "legs": [
        {
          "leg_type": "asset_delivery",
          "instrument_id": "0xBondTokenAddress",
          "quantity": "1000",
          "direction": "receive"
        },
        {
          "leg_type": "payment",
          "instrument_id": "USDC",
          "quantity": "950000",
          "direction": "deliver"
        }
      ],
      "timeout_at": "2026-03-20T12:00:00Z",
      "idempotency_key": "repo-buyer-001",
      "trade_type": "repo_open",
      "repo_terms": {
        "tenor_days": 30,
        "rate_bps": 500,
        "haircut_bps": 500,
        "margin_band_lower": "0.95",
        "margin_band_upper": "1.05"
      }
    }'
  ```

  ```typescript TypeScript SDK theme={null}
  const buyerInstruction = await buyerClient.instructions.submit({
    idempotencyKey: buyerClient.generateIdempotencyKey(),
    tradeReference: "KS-abc123...",
    templateSlug: "dvp-standard",
    role: "buyer",
    party: {
      externalReference: "cash-lender-002",
      name: "Beta Capital",
      walletAddress: "0xBuyerWallet...",
      chainId: 11155111,
    },
    legs: [
      { legType: "asset_delivery", instrumentId: "0xBondTokenAddress", quantity: "1000", direction: "receive" },
      { legType: "payment", instrumentId: "USDC", quantity: "950000", direction: "deliver" },
    ],
    timeoutAt: "2026-03-20T12:00:00Z",
    tradeType: "repo_open",
    repoTerms: {
      tenorDays: 30,
      rateBps: 500,
      haircutBps: 500,
      marginBandLower: "0.95",
      marginBandUpper: "1.05",
    },
  });
  ```

  ```python Python SDK theme={null}
  buyer_instruction = await buyer_client.instructions.submit({
      "trade_reference": "KS-abc123...",
      "template_slug": "dvp-standard",
      "role": "buyer",
      "party": {
          "external_reference": "cash-lender-002",
          "name": "Beta Capital",
          "wallet_address": "0xBuyerWallet...",
          "chain_id": 11155111,
      },
      "legs": [
          {"leg_type": "asset_delivery", "instrument_id": "0xBondTokenAddress", "quantity": "1000", "direction": "receive"},
          {"leg_type": "payment", "instrument_id": "USDC", "quantity": "950000", "direction": "deliver"},
      ],
      "timeout_at": "2026-03-20T12:00:00Z",
      "idempotency_key": "repo-buyer-001",
      "trade_type": "repo_open",
      "repo_terms": {
          "tenor_days": 30,
          "rate_bps": 500,
          "haircut_bps": 500,
          "margin_band_lower": "0.95",
          "margin_band_upper": "1.05",
      },
  })
  ```
</CodeGroup>

When instructions match, the response shows `status: "matched"` and includes the `settlement_id`.

<Note>
  `timeout_at` controls when the opening settlement times out if not completed.
  Maturity is derived, not passed: the closing settlement is due `tenor_days` after the opening settlement is created.
  The closing leg's repayment amount is also derived - from `tenor_days`, `rate_bps`, and the opening payment-leg quantity - so you never pass it explicitly.
</Note>

## Step 2: Repo-specific instruction fields

| Field                                                | Required for repo\_open | Description                                                                         |
| ---------------------------------------------------- | ----------------------- | ----------------------------------------------------------------------------------- |
| `trade_type`                                         | Yes                     | Must be `"repo_open"` (`"repo_close"` is auto-generated at maturity, not submitted) |
| `repo_terms.tenor_days`                              | Yes                     | Repo tenor; maturity = opening creation time + tenor                                |
| `repo_terms.rate_bps`                                | Yes                     | Repo rate in basis points; drives the derived repayment amount                      |
| `repo_terms.haircut_bps`                             | Yes                     | Collateral haircut in basis points                                                  |
| `repo_terms.margin_band_lower` / `margin_band_upper` | Yes                     | Margin band around the collateral value                                             |

## Step 3: Opening settlement processes

The matched instructions create a settlement with:

* `trade_type: "repo_open"`
* `repo_terms` stored on the settlement
* Standard DvP flow: compliance screening, escrow deposits, atomic swap

The settlement engine processes it automatically through all stages.

## Step 4: Await maturity

The opening settlement finalizes. KeyStone derives the maturity as the opening settlement's creation time plus `tenor_days` and checks it on a schedule. When maturity arrives, the system automatically creates the closing settlement.

### Triggering maturity early (admin only)

Administrators can trigger maturity before the scheduled date:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.keystoneos.xyz/v1/admin/settlements/$OPENING_ID/trigger-maturity \
    -H "Authorization: Bearer $ADMIN_TOKEN"
  ```

  ```typescript TypeScript SDK theme={null}
  await client.settlements.triggerMaturity("550e8400-...");
  ```

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

## Step 5: Closing settlement auto-created

At maturity, KeyStone auto-creates two matching instructions for the closing leg (reversed roles and directions) - no party action is required to create it. The closing settlement then goes through the full flow: compliance re-screening, deposits to escrow, autonomous execution.

* **Reversed roles**: Opening seller becomes closing buyer, and vice versa
* **Reversed directions**: Deliver becomes receive, receive becomes deliver
* **Repayment amount**: The closing payment leg is derived from `tenor_days`, `rate_bps`, and the opening payment quantity (principal + interest)
* **Linked**: `linked_settlement_id` ties the closing settlement to its opening (and `repo_terms.close_leg_settlement_id` on the opening points forward)

## Step 6: Closing settlement completes

The closing settlement follows the same standard DvP flow:

1. Compliance screening
2. Escrow deposits (buyer deposits bonds, seller deposits USDC with interest)
3. Atomic swap (bonds return to seller, USDC + interest returns to buyer)
4. Settlement finalizes

Your webhook endpoint receives `settlement.state.finalized` for the closing settlement.

## Step 7: Query related settlements

At any point, you can query both legs of a repo:

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

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

  console.log(`Opening: ${related.opening.state}`);
  console.log(`Closing: ${related.closing?.state}`);
  ```

  ```python Python SDK theme={null}
  related = await client.settlements.related("550e8400-...")

  print(f"Opening: {related.opening.state}")
  print(f"Closing: {related.closing.state if related.closing else 'pending'}")
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "opening": {
    "id": "a1b2c3d4-...",
    "trade_type": "repo_open",
    "state": "FINALIZED",
    "linked_settlement_id": null,
    "repo_terms": {
      "tenor_days": 30,
      "rate_bps": 500,
      "haircut_bps": 500,
      "close_leg_settlement_id": "e5f6g7h8-..."
    }
  },
  "closing": {
    "id": "e5f6g7h8-...",
    "trade_type": "repo_close",
    "state": "FINALIZED",
    "linked_settlement_id": "a1b2c3d4-..."
  }
}
```

(Both objects are full settlement resources; only the repo-relevant fields are shown here. Calling `/related` on either leg returns the same pair.)

## Error scenarios

| Scenario                     | Result                                                                                 |
| ---------------------------- | -------------------------------------------------------------------------------------- |
| Opening compliance rejection | Opening settlement ends in `REJECTED` (pre-deposit). No closing settlement is created. |
| Opening deposit timeout      | Opening settlement times out. Deposits reclaimable. No closing created.                |
| Closing compliance rejection | Closing settlement ends in `REJECTED`. Opening remains finalized.                      |
| Closing deposit timeout      | Closing settlement times out. Deposits reclaimable. Manual resolution needed.          |

See [Webhooks](/guides/webhooks) for setup instructions.
