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

# End-to-End Examples

> Full spot and perps flows with the TypeScript SDK: authenticate, deposit, trade, withdraw, and manage a leveraged position

Two runnable walkthroughs with `@0xmonaco/core`: a spot flow (authenticate, deposit, withdraw, place an order) and a perps flow (fund a parent margin account, open a 5x long, attach TP/SL, close). For a React app, see [Build a Trading App](https://docs.0xmonaco.com/examples/build-trading-app.md).

## Installation

```bash theme={null}
npm install @0xmonaco/core viem
```

## Spot flow

```typescript theme={null}
import { MonacoSDK } from '@0xmonaco/core';
import { createWalletClient, custom, parseUnits } from 'viem';
import { sei } from 'viem/chains';

async function completeMonacoIntegration() {
  try {
    // 1. Request account access
    const [account] = await window.ethereum.request({ 
      method: 'eth_requestAccounts' 
    });

    // 2. Initialize SDK with wallet
    const walletClient = createWalletClient({
      account,
      chain: sei,
      transport: custom(window.ethereum)
    });

    const sdk = new MonacoSDK({
      walletClient,
      network: 'mainnet',
      seiRpcUrl: 'https://evm-rpc.sei-apis.com', // public RPC — use a private provider in production
    });

    // 3. Authenticate (registers a session key; every authenticated request is signed).
    //    Pass connectWebSocket: true to also open the realtime stream (off by default).
    console.log('Authenticating...');
    const authState = await sdk.login('your-client-id', { connectWebSocket: true });
    console.log('Authenticated as:', authState.user.address);

    // 4. Get trading pair to access asset IDs
    // Asset IDs come from trading pairs, not balances
    const usdcPair = await sdk.market.getTradingPairBySymbol('ETH/USDC');
    if (!usdcPair) {
      throw new Error('Trading pair not found');
    }

    // For USDC (the quote token in ETH/USDC):
    const assetId = usdcPair.quoteAssetId;  // All vault operations use assetId
    const decimals = 6; // USDC decimals

    // 5. Check token balance
    const balance = await sdk.profile.getUserBalanceByAssetId(assetId);
    console.log('Available balance:', balance.availableBalance, balance.symbol);
    console.log('Locked balance:', balance.lockedBalance, balance.symbol);

    // 6. Deposit tokens (if you have them)
    const depositAmount = parseUnits('10', decimals);
    
    // Check if approval is needed
    const needsApproval = await sdk.vault.needsApproval(assetId, depositAmount);
    if (needsApproval) {
      console.log('Approving tokens...');
      const approvalResult = await sdk.vault.approve(assetId, depositAmount);
      console.log('Approval transaction:', approvalResult.hash);
    }

    // Deposit tokens
    console.log('Depositing tokens...');
    const depositResult = await sdk.vault.deposit(assetId, depositAmount);
    console.log('Deposit transaction:', depositResult.hash);

    // 7. Check updated balance
    const newBalance = await sdk.profile.getUserBalanceByAssetId(assetId);
    console.log('Available balance:', newBalance.availableBalance, newBalance.symbol);
    console.log('Total balance:', newBalance.totalBalance, newBalance.symbol);

    // 8. Withdraw tokens (optional)
    const withdrawAmount = parseUnits('5', decimals);
    console.log('Withdrawing tokens...');
    const withdrawResult = await sdk.vault.withdraw(assetId, withdrawAmount);
    console.log('Withdrawal transaction:', withdrawResult.hash);

    // Check balance after withdrawal
    const balanceAfterWithdraw = await sdk.profile.getUserBalanceByAssetId(assetId);
    console.log('Available balance:', balanceAfterWithdraw.availableBalance, balanceAfterWithdraw.symbol);
    console.log('Total balance:', balanceAfterWithdraw.totalBalance, balanceAfterWithdraw.symbol);

    // 9. Get trading pair (reuse the same one for trading)
    const tradingPair = usdcPair;  // ETH/USDC from step 4

    // 10. Place a trading order
    console.log('Placing limit order...');
    const limitOrder = await sdk.trading.placeLimitOrder(
      tradingPair.id,  // Trading pair UUID
      'BUY',           // Side  
      '0.1',           // Quantity (0.1 ETH)
      '2000'           // Price ($2000)
    );
    console.log('Order placed:', limitOrder.orderId);

    // 11. Check order status (optional)
    console.log('Order details:', limitOrder);

  } catch (error) {
    console.error('Error:', error.message);
    
    // Handle specific error types
    if (error.statusCode === 401) {
      console.log('Authentication failed - check client ID');
    } else if (error.statusCode === 403) {
      console.log('Session expired or unauthorized - need to re-authenticate');
    } else {
      console.log('Other error:', error);
    }
  }
}

// Run the complete integration
completeMonacoIntegration();
```

**Authentication**

* Use `sdk.login(clientId)` - it registers a local session key and signs every authenticated request (public market reads are unsigned); there are no tokens to copy or refresh
* The WebSocket is NOT auto-connected by default — pass `sdk.login(clientId, { connectWebSocket: true })` (or connect explicitly) before using `sdk.ws.orders()` to subscribe
* Handle 401/403 status codes for authentication errors

**Deposits & Withdrawals**

* **Get `assetId` from trading pairs** via `sdk.market.getTradingPairBySymbol()` - use `quoteAssetId` or `baseAssetId`
* **`assetId`** (UUID) is used for vault operations: `approve()`, `deposit()`, `withdraw()`, `getAllowance()`, and `needsApproval()`
* **Check balances** using `sdk.profile.getUserBalanceByAssetId(assetId)` for detailed balance info (available, locked, total)
* Always check `needsApproval()` before depositing
* Use `parseUnits()` with correct decimals for token amounts
* Vault operations require authentication

**Trading**

* All amounts are strings (e.g., `'1.5'`, `'2000.50'`)
* Trading operations require authentication
* Orders return an `orderId` for tracking
* Time-In-Force (TIF) options: `'GTC'` (default), `'IOC'`, or `'FOK'`
  * **GTC**: Order stays active until filled or canceled
  * **IOC**: Fill immediately, cancel unfilled portion
  * **FOK**: Fill completely or reject entirely

**Error Handling**

* Check `error.statusCode` for HTTP errors (401, 403)
* All operations can throw `APIError`, `ContractError`, etc.

## Perps flow

For concepts, see [Margin](https://docs.0xmonaco.com/trading-mechanics/perps.md), [Account Vault](https://docs.0xmonaco.com/developers/vault.md#deposit-directly-to-perps-collateral), and [Positions](https://docs.0xmonaco.com/developers/positions.md).

```typescript theme={null}
import { MonacoSDK } from "@0xmonaco/core";
import { createWalletClient, custom, parseUnits } from "viem";
import { sei } from "viem/chains";

async function perpFlowExample() {
  // ---------------------------------------------------------------------------
  // 1. Connect wallet and initialize SDK
  // ---------------------------------------------------------------------------
  const [walletAccount] = await window.ethereum.request({
    method: "eth_requestAccounts",
  });

  const walletClient = createWalletClient({
    account: walletAccount,
    chain: sei,
    transport: custom(window.ethereum),
  });

  const sdk = new MonacoSDK({
    walletClient,
    network: "mainnet",
    seiRpcUrl: "https://evm-rpc.sei-apis.com", // public RPC — use a private provider in production
  });

  // ---------------------------------------------------------------------------
  // 2. Authenticate
  // ---------------------------------------------------------------------------
  const auth = await sdk.login("your-client-id");
  console.log("Authenticated as", auth.user.address);

  // ---------------------------------------------------------------------------
  // 3. Deposit USDC into Monaco's vault (skip if collateral is already on-chain)
  // ---------------------------------------------------------------------------
  // Get USDC asset metadata from any pair that uses it as quote
  const ethUsdcPair = await sdk.market.getTradingPairBySymbol("ETH/USDC");
  if (!ethUsdcPair) throw new Error("ETH/USDC pair not found");

  const usdcAssetId = ethUsdcPair.quoteAssetId;
  const usdcDecimals = ethUsdcPair.quoteDecimals;

  // Approve and deposit 5,000 USDC into the vault
  const depositAmount = parseUnits("5000", usdcDecimals);
  if (await sdk.vault.needsApproval(usdcAssetId, depositAmount)) {
    await sdk.vault.approve(usdcAssetId, depositAmount);
  }
  await sdk.vault.deposit(usdcAssetId, depositAmount);

  // ---------------------------------------------------------------------------
  // 4. Find a perp trading pair
  // ---------------------------------------------------------------------------
  // Perp pairs are distinguished by marketType === "MARGIN"
  const { tradingPairs } = await sdk.market.getPaginatedTradingPairs({
    pageSize: 100,
  });
  const perpPair = tradingPairs.find(
    (p) => p.marketType === "MARGIN" && p.baseToken === "ETH",
  );
  if (!perpPair) throw new Error("No ETH perp pair available");

  const tradingPairId = perpPair.id;
  console.log(`Trading on ${perpPair.symbol} (${tradingPairId})`);

  // ---------------------------------------------------------------------------
  // 5. Fund the parent margin account with 1,000 USDC.
  // ---------------------------------------------------------------------------
  await sdk.marginAccounts.transferCollateralToParentMarginAccount({
    asset: "USDC",
    amount: "1000",
  });

  // Verify funding succeeded without storing a margin account id.
  const summary = await sdk.marginAccounts.getParentMarginAccountSummary();
  console.log(`Equity: ${summary.equity}, free: ${summary.freeCollateral}`);

  // ---------------------------------------------------------------------------
  // 6. Pre-flight the order with simulateRiskBucketOrderRisk
  // ---------------------------------------------------------------------------
  // Open a 5x long ETH at $2,000 with 1.5 ETH size
  const orderQuantity = "1.5";
  const limitPrice = "2000";
  const leverage = "5";

  const risk = await sdk.marginAccounts.simulateRiskBucketOrderRisk({
    tradingPairId,
    side: "BUY",
    orderType: "LIMIT",
    price: limitPrice,
    quantity: orderQuantity,
    leverage,
  });

  if (!risk.accepted) {
    console.error("Order would be rejected:", risk.rejectReason);
    return;
  }
  console.log(
    `Estimated liquidation: ${risk.estimatedLiquidationPrice}, ` +
      `free after: ${risk.freeCollateralAfter}`,
  );

  // ---------------------------------------------------------------------------
  // 7. Place the perp order
  // ---------------------------------------------------------------------------
  const order = await sdk.trading.placeLimitOrder(
    tradingPairId,
    "BUY",
    orderQuantity,
    limitPrice,
    {
      tradingMode: "MARGIN",
      leverage,
    },
  );
  console.log(`Order ${order.orderId} submitted`);

  // ---------------------------------------------------------------------------
  // 8. Wait for the position to open via websocket
  // ---------------------------------------------------------------------------
  await sdk.ws.connect();

  const positionId: string = await new Promise((resolve, reject) => {
    const timeout = setTimeout(
      () => reject(new Error("Order didn't fill in 30s")),
      30_000,
    );

    const unsubscribe = sdk.ws.userOrders((evt) => {
      if (evt.orderId !== order.orderId) return;
      if (evt.eventType === "OrderFilled" || evt.eventType === "OrderPartiallyFilled") {
        clearTimeout(timeout);
        unsubscribe();
        // Position lookup happens after a small settle delay
        setTimeout(async () => {
          const { positions } = await sdk.positions.listPositions({
            tradingPairId: tradingPairId,
            status: "OPEN",
          });
          const pos = positions[0];
          if (!pos) reject(new Error("Position not found after fill"));
          else resolve(pos.positionId);
        }, 500);
      } else if (evt.eventType === "OrderRejected" || evt.eventType === "OrderCancelled") {
        clearTimeout(timeout);
        unsubscribe();
        reject(new Error(`Order ${evt.eventType}: ${(evt.data as any).reason}`));
      }
    });
  });
  console.log(`Position opened: ${positionId}`);

  // ---------------------------------------------------------------------------
  // 9. Inspect live risk
  // ---------------------------------------------------------------------------
  const positionRisk = await sdk.positions.getPositionRisk(positionId);
  console.log({
    mark: positionRisk.markPrice,
    liquidation: positionRisk.liquidationPrice || "unavailable",
    pnl: positionRisk.unrealizedPnl,
    marginRatio: positionRisk.marginRatio,
  });

  // ---------------------------------------------------------------------------
  // 10. Attach TP and SL (OCO group)
  // ---------------------------------------------------------------------------
  const tpSl = await sdk.positions.attachPositionTpSl(positionId, {
    takeProfit: { triggerPrice: "2200", orderType: "MARKET" },
    stopLoss: { triggerPrice: "1900", orderType: "MARKET" },
    oco: true,
  });
  console.log(
    `TP: ${tpSl.takeProfitOrderId}, SL: ${tpSl.stopLossOrderId}`,
  );

  // Subscribe to conditional-order lifecycle (optional — useful for UI updates)
  const unsubConditionals = sdk.ws.conditionalOrders((evt) => {
    console.log(
      `Conditional ${evt.data.conditionalOrderId} → ${evt.data.state} ` +
        `(${evt.data.reason})`,
    );
  });

  // ---------------------------------------------------------------------------
  // 11. Manual close (if you don't want to wait for TP/SL)
  // ---------------------------------------------------------------------------
  // Half close at limit
  await sdk.positions.closePosition(positionId, {
    closeType: "LIMIT",
    limitPrice: "2050",
    quantity: "0.75",
  });

  // Or full market close
  // await sdk.positions.closePosition(positionId, { closeType: "MARKET" });

  // ---------------------------------------------------------------------------
  // 12. Cleanup
  // ---------------------------------------------------------------------------
  unsubConditionals();
  sdk.ws.disconnect();
}

perpFlowExample().catch(console.error);
```

### What the perps flow covers

1. **Deposit** — using the standard spot vault flow; collateral has to land on Monaco before it can be transferred to a margin account.
2. **Trading pair lookup** — perps are filtered by `marketType === "MARGIN"`.
3. **Parent margin account funding** — one collateral asset per account; USDC is the default.
4. **Preflight via `simulateRiskBucketOrderRisk`** — never place a non-trivial perp order without checking acceptance and projected liquidation.
5. **Order placement with perp options** — `tradingMode: "MARGIN"` and `leverage` are the key perp options; `side` sets the one-way direction.
6. **Position lookup after fill** — order events stream over `userOrders`; the position itself appears in `listPositions` shortly after.
7. **Live risk inspection** — `getPositionRisk` is the right call for live UI updates (cheaper than `getPosition`).
8. **TP/SL via `attachPositionTpSl`** — pass `oco: true` so the two legs cancel each other on trigger.
9. **Conditional order lifecycle subscription** — `sdk.ws.conditionalOrders` streams TP/SL state changes.
10. **Close** — partial or full, MARKET or LIMIT.

### Common variations

* **Reduce-only manual close.** Instead of `closePosition`, use `placeMarketOrder` with `reduceOnly: true` — useful when you want to apply slippage protection or specific TIF.
* **Withdraw collateral.** After closing all positions, use `transferCollateralFromParentMarginAccount` to move USDC back to the wallet, then `sdk.vault.withdraw(...)` to leave Monaco entirely.

## Reference links

* [Authentication](https://docs.0xmonaco.com/sdk/typescript/auth.md)
* [Order Management](https://docs.0xmonaco.com/developers/trade.md)
* [Margin Accounts SDK reference](https://docs.0xmonaco.com/sdk/typescript/margin-accounts.md)
* [Positions SDK reference](https://docs.0xmonaco.com/sdk/typescript/positions.md)
* [WebSockets reference](https://docs.0xmonaco.com/sdk/typescript/websockets.md)
* [REST API](https://docs.0xmonaco.com/api-reference)
* [v0.7.0 release notes](https://docs.0xmonaco.com/changelog.md#v0-7-0)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.