# Add to an open options or stock trade

`POST https://app.skylit.ai/api/nexus/v1/trades/{id}/adds`

API: Nexus.

Already in a trade and want more? Send an add to the trade's id instead of a second open. A second open on the same contract answers `409 duplicate_position`, and its `tradeId` is the trade to add to.

- It fills like an open: options at the live ask, stocks at the live price. Send `price` for your own price when it's inside the market, and `ifOutside` for what happens when it isn't, same as an open.
- Your average, totals and P/L update exactly the way they do when you add in Nexus, and the paper wallet pays. A trade on your agent account pays from the agent wallet and stays private.
- Market orders only. Each add is 1 to 1,000 contracts or 1 to 100,000 shares, and a position can't grow past that through the API (`409 position_size_limit`).
- Not enough buying power is `422 insufficient_buying_power`. A quote older than 15 seconds is `503 stale_quote`: nothing was added, so try again in a moment.
- Send a `clientOrderId`. If your bot retries, the add happens once and the repeat answers with the trade and `meta.idempotentReplay: true`.
- An add to a test trade's id is a test add: checked and priced like a real one, and it only touches your test log. `"test": true` on a real trade adds nothing.

It answers `200` with the trade. `meta.fill` shows the price, how many you added and where the price came from.

## Authentication

Send your Skylit API key as a bearer token: `Authorization: Bearer <key>`. No other header is accepted.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string (uuid) | yes | The trade's id, from the open or the list. |
| `Idempotency-Key` | header | string | no | Your `clientOrderId`, as a header instead of a body field. If you send both they must match. |

## Request body

`application/json`

```json
{
  "quantity": 0,
  "price": 0,
  "ifOutside": "reject",
  "orderType": "market",
  "clientOrderId": "string",
  "test": false
}
```

## Example request

```bash
curl "https://app.skylit.ai/api/nexus/v1/trades/6f1c2a4e-8b1d-4c39-9a51-2d7e0b3c9f10/adds" \
  -H "Authorization: Bearer $SKYLIT_API_KEY"
```

## Responses

### 200

The trade after the add, with `meta.fill`.

Added 2 at the live ask of 1.60. The average dropped from 1.84 to 1.72.:

```json
{
  "data": {
    "id": "6f1c2a4e-8b1d-4c39-9a51-2d7e0b3c9f10",
    "userId": "0b8e5d2c-41a7-4f6e-9c3b-7a1d2e4f5a60",
    "ticker": "SPY",
    "strike": 600,
    "expiration": "2026-10-16",
    "direction": "call",
    "assetClass": "options",
    "averageEntryPrice": 1.72,
    "totalQuantity": 4,
    "remainingQuantity": 4,
    "status": "active",
    "entryDate": "2026-10-09T14:32:05Z",
    "source": "api"
  },
  "meta": {
    "fill": {
      "price": 1.6,
      "priceSource": "market",
      "quantity": 2
    },
    "clientOrderId": "my-bot-add-0001"
  }
}
```

### 400

The request was refused before anything was traded. Codes: `bad_request`, `bad_contract`, `invalid_quantity`, `invalid_price`, `unsupported_asset_class`, `unsupported_order_type`, `only_market_orders`, `limit_price_required` (a limit with no `limitPrice`), `invalid_limit_price` (not in cents, or outside 0.01 to 99,999.99 for options or 999,999.99 for stocks), `stop_price_required` (a stop with no `stopPrice`), `invalid_stop_price` (not in cents, or outside 0.01 to 999,999.99), `invalid_take_profit`, `test_orders_unavailable`, `test_modify_unavailable`.

A typo in the body.:

```json
{
  "error": {
    "code": "bad_request",
    "message": "Unknown field \"quantitty\". See the trades API docs for the fields you can send."
  }
}
```

### 401

No key, or a key that isn't valid. Codes: `missing_api_key`, `invalid_api_key`.

No key sent.:

```json
{
  "error": {
    "code": "missing_api_key",
    "message": "Send your Skylit API key in the Authorization header: Authorization: Bearer YOUR_SKYLIT_API_KEY."
  }
}
```

### 403

The key works but the account can't do this. Codes: `account_suspended`, `nexus_access_denied`, `futures_access_denied`.

The account doesn't include Nexus.:

```json
{
  "error": {
    "code": "nexus_access_denied",
    "message": "This Skylit account doesn't include Nexus, so it can't place Nexus trades."
  }
}
```

### 404

Not on your account. Codes: `trade_not_found`, `account_not_found`, `order_not_found`.

Not your trade, or no such trade.:

```json
{
  "error": {
    "code": "trade_not_found",
    "message": "No trade with that id on your account."
  }
}
```

### 409

The order clashes with what you hold or sent before. Codes: `duplicate_position` (with `tradeId`: add to it instead), `trade_closed`, `open_position_limit` (open positions plus resting opens through the API are at 50), `working_order_limit` (50 options and stock orders already resting through the API), `position_size_limit` (an add would take the position past 1,000 contracts or 100,000 shares), `client_order_id_used`, `request_in_progress`, `account_locked`, `account_busy`, `account_ended`, `order_not_working` (it already filled, expired, or was cancelled or rejected), `stop_triggered` (a stop that's been set off is filling now, so it can't be cancelled or changed).

You already hold this contract.:

```json
{
  "error": {
    "code": "duplicate_position",
    "message": "You already hold an open position on this contract. Add to it with POST /api/nexus/v1/trades/{id}/adds (the id is tradeId), or close it first.",
    "tradeId": "6f1c2a4e-8b1d-4c39-9a51-2d7e0b3c9f10"
  }
}
```

### 422

Read fine, but the market or the account says no. Codes: `market_closed`, `contract_expired`, `contract_not_offered`, `price_outside_market`, `insufficient_buying_power`, `account_not_tradable`, `account_ambiguous`, `reduce_only_would_open`, `order_refused`, `order_rejected` (a resting order that tried to fill right away and couldn't; `orderId` points to it). A resting order that can't be covered answers `insufficient_buying_power` with `orderId` too: it's recorded as rejected.

Outside market hours.:

```json
{
  "error": {
    "code": "market_closed",
    "message": "The market is closed for this contract right now, so nothing was filled."
  }
}
```

### 429

Over a rate limit. Wait `Retry-After` seconds, then retry. Codes: `rate_limited`, and `stream_limit_reached` (too many live streams open: 3 per key, 6 per account).

Headers: `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.

Too many writes from this key.:

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests (limit 30). Slow down and retry in 12 seconds."
  }
}
```

### 500

Something went wrong on our side. If you sent a `clientOrderId`, retry with the same one. Code: `internal_error`.

Retry with the same clientOrderId.:

```json
{
  "error": {
    "code": "internal_error",
    "message": "Something went wrong on our side. If you sent a clientOrderId, retry with the same one (it can't fill twice). Otherwise check your account before retrying."
  }
}
```

### 503

Try again in a moment (honour `Retry-After` when it's sent). Codes: `stale_quote` (the quote, or a stock's last trade, is more than 15 seconds old, so nothing filled), `no_live_price`, `rules_pending`, `unavailable`, `auth_unavailable`, `access_check_unavailable`, `api_keys_unavailable`, `trades_api_disabled`, `stream_unavailable` (the live stream isn't on, or the server is restarting: try again shortly, or poll the reads).

Headers: `Retry-After`.

No live price right now.:

```json
{
  "error": {
    "code": "no_live_price",
    "message": "There's no live price for this contract right now, so nothing was filled. Try again in a moment."
  }
}
```
