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

# Create Order

> Create trigger orders with vault-based deposits. Supports single limit orders, OCO (take-profit/stop-loss), and OTOCO (conditional chains).

Creating an order in V2 is a two-step process: craft and sign a deposit transaction, then submit it alongside your order parameters.

<Tip>
  For a working reference of the full order creation flow, see how [jup.ag](https://jup.ag) handles it. The frontend implements the same API with validation, error handling, and UX patterns you can use as a guide.
</Tip>

## Prerequisites

Signing deposit transactions requires `@solana/web3.js`:

```bash theme={null}
npm install @solana/web3.js
```

## End-to-End Flow

```
1. Get vault          →  GET /v2/vault (or /v2/vault/register on first use)
2. Craft deposit      →  POST /v2/deposit/craft
3. Sign deposit tx    →  (client-side)
4. Create order       →  POST /v2/orders/price (with signed tx)
```

## Step 1: Get Your Vault

Retrieve your vault, or register one if this is your first time. The vault is a Privy-managed custodial account that holds deposits for your orders.

```typescript theme={null}
let vaultResponse = await fetch('https://api.jup.ag/trigger/v2/vault', {
  headers: {
    'x-api-key': 'your-api-key',
    'Authorization': `Bearer ${token}`,
  },
});

// First time user — register a new vault
if (!vaultResponse.ok) {
  vaultResponse = await fetch('https://api.jup.ag/trigger/v2/vault/register', {
    headers: {
      'x-api-key': 'your-api-key',
      'Authorization': `Bearer ${token}`,
    },
  });
}

const vault = await vaultResponse.json();
// { userPubkey: "...", vaultPubkey: "...", privyVaultId: "..." }
```

## Step 2: Craft a Deposit Transaction

The deposit endpoint builds an unsigned transaction that transfers tokens from your wallet to your vault.

```typescript theme={null}
const depositResponse = await fetch('https://api.jup.ag/trigger/v2/deposit/craft', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'your-api-key',
    'Authorization': `Bearer ${token}`,
  },
  body: JSON.stringify({
    inputMint: 'So11111111111111111111111111111111111111112',  // SOL
    outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',  // USDC
    userAddress: walletAddress,
    amount: '1000000000',  // 1 SOL in lamports
  }),
});

const deposit = await depositResponse.json();
```

**Response:**

```json theme={null}
{
  "transaction": "Base64EncodedUnsignedTransaction...",
  "requestId": "01234567-89ab-cdef-0123-456789abcdef",
  "receiverAddress": "VaultPublicKey...",
  "mint": "So11111111111111111111111111111111111111112",
  "amount": "1000000000",
  "tokenDecimals": 9
}
```

<Note>
  The vault address is automatically resolved from your JWT. You do not specify it in the request.
</Note>

## Step 3: Sign the Deposit Transaction

```typescript theme={null}
import { VersionedTransaction } from '@solana/web3.js';

const transaction = VersionedTransaction.deserialize(
  Buffer.from(deposit.transaction, 'base64')
);
const signedTransaction = await wallet.signTransaction(transaction);
const depositSignedTx = Buffer.from(signedTransaction.serialize()).toString('base64');
```

## Step 4: Create the Order

Submit the signed deposit alongside your order parameters. The order type determines which fields are required.

### Single Order (Limit)

A single order triggers when the price of `triggerMint` crosses above or below the target price.

```typescript theme={null}
const orderResponse = await fetch('https://api.jup.ag/trigger/v2/orders/price', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'your-api-key',
    'Authorization': `Bearer ${token}`,
  },
  body: JSON.stringify({
    orderType: 'single',
    depositRequestId: deposit.requestId,
    depositSignedTx: depositSignedTx,
    userPubkey: walletAddress,
    inputMint: 'So11111111111111111111111111111111111111112',
    inputAmount: '1000000000',
    outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
    triggerMint: 'So11111111111111111111111111111111111111112',
    triggerCondition: 'above',  // 'above' or 'below'
    triggerPriceUsd: 200.00,
    slippageBps: 100,  // 1%
    expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000,  // 7 days
  }),
});

const order = await orderResponse.json();
// { id: "order-uuid", txSignature: "..." }
```

### OCO Order (One-Cancels-Other)

An OCO order creates a take-profit and stop-loss pair sharing one deposit. When one side fills, the other cancels automatically.

```typescript theme={null}
const orderResponse = await fetch('https://api.jup.ag/trigger/v2/orders/price', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'your-api-key',
    'Authorization': `Bearer ${token}`,
  },
  body: JSON.stringify({
    orderType: 'oco',
    depositRequestId: deposit.requestId,
    depositSignedTx: depositSignedTx,
    userPubkey: walletAddress,
    inputMint: 'So11111111111111111111111111111111111111112',
    inputAmount: '1000000000',
    outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
    triggerMint: 'So11111111111111111111111111111111111111112',
    tpPriceUsd: 250.00,    // Take profit price
    slPriceUsd: 150.00,    // Stop loss price
    tpSlippageBps: 100,
    slSlippageBps: 100,
    expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000,
  }),
});
```

<Note>
  The take-profit price must be greater than the stop-loss price.
</Note>

### OTOCO Order (One-Triggers-One-Cancels-Other)

An OTOCO order has a parent trigger that executes first. Once filled, it automatically activates a TP/SL pair (OCO) on the output tokens.

```typescript theme={null}
const orderResponse = await fetch('https://api.jup.ag/trigger/v2/orders/price', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'your-api-key',
    'Authorization': `Bearer ${token}`,
  },
  body: JSON.stringify({
    orderType: 'otoco',
    depositRequestId: deposit.requestId,
    depositSignedTx: depositSignedTx,
    userPubkey: walletAddress,
    inputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
    inputAmount: '200000000',  // 200 USDC
    outputMint: 'So11111111111111111111111111111111111111112',
    triggerMint: 'So11111111111111111111111111111111111111112',
    triggerCondition: 'below',
    triggerPriceUsd: 180.00,   // Entry: buy SOL when it drops to \$180
    tpPriceUsd: 220.00,       // Take profit at \$220
    slPriceUsd: 160.00,       // Stop loss at \$160
    slippageBps: 100,         // Parent order slippage
    tpSlippageBps: 100,
    slSlippageBps: 100,
    expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1000,  // 30 days
  }),
});
```

## Order Parameters Reference

### Common Fields (All Order Types)

| Parameter          | Type     | Required | Description                               |
| :----------------- | :------- | :------- | :---------------------------------------- |
| `orderType`        | `string` | Yes      | `single`, `oco`, or `otoco`               |
| `depositRequestId` | `string` | Yes      | From the deposit craft response           |
| `depositSignedTx`  | `string` | Yes      | Base64-encoded signed deposit transaction |
| `userPubkey`       | `string` | Yes      | Your wallet public key                    |
| `inputMint`        | `string` | Yes      | Mint address of the token to sell         |
| `inputAmount`      | `string` | Yes      | Amount in smallest unit (lamports, etc.)  |
| `outputMint`       | `string` | Yes      | Mint address of the token to buy          |
| `triggerMint`      | `string` | Yes      | Mint address to monitor for price trigger |
| `expiresAt`        | `number` | Yes      | Expiration timestamp in milliseconds      |

### Single Order Fields

| Parameter          | Type     | Required | Description                                  |
| :----------------- | :------- | :------- | :------------------------------------------- |
| `triggerCondition` | `string` | Yes      | `above` or `below`                           |
| `triggerPriceUsd`  | `number` | Yes      | USD price that triggers execution            |
| `slippageBps`      | `number` | No       | Slippage tolerance in basis points (0-10000) |

### OCO Order Fields

| Parameter       | Type     | Required | Description                         |
| :-------------- | :------- | :------- | :---------------------------------- |
| `tpPriceUsd`    | `number` | Yes      | Take-profit trigger price (USD)     |
| `slPriceUsd`    | `number` | Yes      | Stop-loss trigger price (USD)       |
| `tpSlippageBps` | `number` | No       | Take-profit slippage (basis points) |
| `slSlippageBps` | `number` | No       | Stop-loss slippage (basis points)   |

### OTOCO Order Fields

| Parameter          | Type     | Required | Description                          |
| :----------------- | :------- | :------- | :----------------------------------- |
| `triggerCondition` | `string` | Yes      | Parent trigger: `above` or `below`   |
| `triggerPriceUsd`  | `number` | Yes      | Parent trigger price (USD)           |
| `tpPriceUsd`       | `number` | Yes      | Take-profit price after parent fills |
| `slPriceUsd`       | `number` | Yes      | Stop-loss price after parent fills   |
| `slippageBps`      | `number` | No       | Parent order slippage                |
| `tpSlippageBps`    | `number` | No       | Take-profit slippage                 |
| `slSlippageBps`    | `number` | No       | Stop-loss slippage                   |

## Default Slippage

If slippage is not specified, defaults vary by order type and trigger condition:

| Order side                                         | Default slippage                                      |
| :------------------------------------------------- | :---------------------------------------------------- |
| **Take-profit / buy below** (buying into strength) | Auto slippage via RTSE (Real-Time Slippage Estimator) |
| **Stop-loss / buy above** (selling into weakness)  | 20% (2000 bps)                                        |

Stop-loss orders use a higher default because execution certainty is more important than price precision when cutting losses.

## Validation Rules

* Minimum order size: 10 USD
* Input and output mints must be different
* Slippage: 0-10000 basis points
* `expiresAt` is required and must be a future timestamp (milliseconds)
* OCO/OTOCO: take-profit price must be greater than stop-loss price

<Note>
  Unlike V1 where orders could exist indefinitely, V2 requires an expiration on every order. Adding a TTL allows the system to prune orders that are unlikely to fill, improving execution quality for active orders. For long-lived orders, use a far-future timestamp (e.g. 30 days).
</Note>

## Response

```json theme={null}
{
  "id": "order-uuid",
  "txSignature": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d..."
}
```

The `txSignature` confirms the deposit transaction landed on-chain. The order is now active and will execute when price conditions are met.
