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

# Getting Started

> Install KeyStone Elements and set up your first settlement integration.

## Installation

Install the packages you need:

<CodeGroup>
  ```bash Hooks only (headless) theme={null}
  npm install @keystoneos/react
  ```

  ```bash With pre-built UI theme={null}
  npm install @keystoneos/react-ui
  ```

  ```bash Server-side helpers theme={null}
  npm install @keystoneos/node
  ```
</CodeGroup>

## 1. Create a Session Token (Backend)

Session tokens are scoped, short-lived JWTs that your frontend uses to call the KeyStone API. Your backend creates them using M2M credentials.

```typescript theme={null}
// your-backend/routes/keystone-session.ts
import { KeystoneClient } from '@keystoneos/sdk';
import { createSessionToken } from '@keystoneos/node';

const keystone = new KeystoneClient({
  clientId: process.env.KEYSTONE_CLIENT_ID,
  clientSecret: process.env.KEYSTONE_CLIENT_SECRET,
  environment: 'production',
});

app.post('/api/keystone/session', async (req, res) => {
  const session = await createSessionToken(keystone, {
    scopes: ['settlements:read', 'settlements:write'],
    metadata: { userId: req.user.id },
  });
  res.json({ token: session.sessionToken });
});
```

## 2. Set Up the Provider (Frontend)

Wrap your app (or the relevant section) with `KeystoneProvider`:

```tsx theme={null}
import { KeystoneProvider } from '@keystoneos/react';

function App() {
  const [token, setToken] = useState<string | null>(null);

  useEffect(() => {
    fetch('/api/keystone/session', { method: 'POST' })
      .then(r => r.json())
      .then(d => setToken(d.token));
  }, []);

  if (!token) return <Loading />;

  return (
    <KeystoneProvider
      sessionToken={token}
      environment="production"
      onTokenExpired={async () => {
        const res = await fetch('/api/keystone/session', { method: 'POST' });
        const data = await res.json();
        return data.token;
      }}
    >
      <YourApp />
    </KeystoneProvider>
  );
}
```

## 3. Use Hooks

Now you can use any hook inside the provider:

```tsx theme={null}
import { useSettlements, getStateInfo } from '@keystoneos/react';

function SettlementDashboard() {
  const { settlements, total, isLoading } = useSettlements();

  if (isLoading) return <Spinner />;

  return (
    <table>
      <thead>
        <tr><th>Reference</th><th>State</th><th>Created</th></tr>
      </thead>
      <tbody>
        {settlements.map(s => {
          const state = getStateInfo(s.state);
          return (
            <tr key={s.id}>
              <td>{s.external_reference}</td>
              <td>{state.label}</td>
              <td>{new Date(s.created_at).toLocaleDateString()}</td>
            </tr>
          );
        })}
      </tbody>
    </table>
  );
}
```

## 4. Submit an Instruction

Create a settlement by submitting your side of the trade. A DvP instruction requires two legs - one for asset delivery and one for payment. The direction of each leg is derived from your role:

```tsx theme={null}
import { useSubmitInstruction } from '@keystoneos/react';

function TradeForm() {
  const { submit, result, isSubmitting, error } = useSubmitInstruction();

  const handleSubmit = async (formData) => {
    const instruction = await submit({
      role: 'seller',
      party: {
        external_reference: formData.accountId,
        name: formData.accountName,
        wallet_address: formData.walletAddress,
      },
      legs: [
        {
          leg_type: 'asset_delivery',
          instrument_id: formData.assetTokenAddress,
          quantity: formData.assetQuantity,
          direction: 'deliver',    // seller delivers asset
          chain_id: formData.chainId,
        },
        {
          leg_type: 'payment',
          instrument_id: formData.paymentTokenAddress,
          quantity: formData.paymentQuantity,
          direction: 'receive',    // seller receives payment
          chain_id: formData.chainId,
        },
      ],
      templateSlug: 'cross_platform_dvp',
      timeoutAt: new Date(Date.now() + 86400000).toISOString(),
    });

    if (instruction.status === 'matched') {
      // Counterparty already submitted - settlement created
      router.push(`/settlements/${instruction.settlementId}`);
    }
  };

  if (result && result.status === 'pending_match') {
    return (
      <div>
        <p>Waiting for counterparty. Share this trade reference:</p>
        <code>{result.tradeReference}</code>
      </div>
    );
  }

  return <YourFormComponent onSubmit={handleSubmit} loading={isSubmitting} error={error} />;
}
```

## 5. Handle Deposits (Tier 2)

For custody wallet integration, provide action delegates:

```tsx theme={null}
<KeystoneProvider
  sessionToken={token}
  actionDelegates={{
    onDepositRequired: async (leg, depositInfo) => {
      // depositInfo contains: calldata, escrowAddress, chainId, tokenAddress, amount
      const result = await fetch('/api/deposit', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          calldata: depositInfo.calldata,
          escrowAddress: depositInfo.escrowAddress,
          chainId: depositInfo.chainId,
        }),
      }).then(r => r.json());

      return { txHash: result.txHash };
    },
  }}
>
```

Your backend receives the calldata and submits it through your custody provider:

```typescript theme={null}
// your-backend/routes/deposit.ts
app.post('/api/deposit', async (req, res) => {
  const { calldata, escrowAddress, chainId } = req.body;

  // Submit to Fireblocks, BitGo, or your signing infrastructure
  const txHash = await fireblocksClient.submitTransaction({
    to: escrowAddress,
    data: calldata,
    chainId,
  });

  res.json({ txHash });
});
```

## 6. Handle Webhooks (Backend)

Set up webhook processing with signature verification:

```typescript theme={null}
import { webhookMiddleware } from '@keystoneos/node';
import express from 'express';

app.post(
  '/webhooks/keystone',
  express.raw({ type: 'application/json' }),
  webhookMiddleware({ secret: process.env.WEBHOOK_SECRET }),
  (req, res) => {
    const { event, data } = req.keystoneEvent;

    switch (event) {
      case 'settlement.state.awaiting_deposits':
        console.log(`Settlement ${data.settlement_id}: ${data.state}`);
        // Trigger deposits, update your OMS, notify traders, etc.
        break;
      case 'settlement.state.finalized':
        console.log(`Settlement finalized: ${data.settlement_id}`);
        break;
    }

    res.sendStatus(200);
  },
);
```

<Card title="Next: Hooks Reference" icon="code" href="/hooks/use-settlement">
  Explore the full hooks API.
</Card>
