Your own holdings, not a public dataset. These are the only `/v1` endpoints that **write**, and the only ones whose answer differs per API key: a portfolio belongs to the account its key belongs to, and nothing in a path, body or query string can name another account. A portfolio you do not own is reported as `404`, exactly like one that does not exist.

The same portfolios are reachable from an AI assistant through the [portfolio MCP tools](/docs/mcp/tools/portfolio) and from your Equibles dashboard. All three read and write the same rows.

## How a lot is recorded

A **lot** is one acquisition: what was bought or sold, how much of it, at what price, and when. Positions are lots rolled up for display, so the original cost and date always stay recoverable.

- **`quantity` is signed.** Positive is long, negative is a short sale or a written (sold-to-open) option. Shares for a stock, contracts for an option.
- **`costPerUnit` is a price, so it is never negative:** what was paid for a long, what was received for a short. The direction is carried by the sign of the quantity alone. For an option it is the premium **per share of the underlying**: two contracts at $12.40 is `quantity: 2`, `costPerUnit: 12.40`, not 1240.
- **An option is identified by its OCC symbol** (`optionContract`). Its expiration, strike, type and contract size are read back from the live options data rather than parsed out of the symbol, so an unknown or expired symbol is rejected instead of stored. Find symbols with the [options endpoints](/docs/api/endpoints/options).
- **Quantities and costs are never restated for a stock split.** Which side of a split a broker's figures were taken on is unknowable here, and guessing would corrupt your cost basis.
- **A sale is a close, not an edit.** Closing records the sale price and date and moves the result into `realizedGain`; editing the quantity down instead loses it. Closing part of a lot splits it, and the remainder keeps its original cost basis.
- All values are **US dollars**. A portfolio holds at most 200 lots, and an account at most 10 portfolios.

## How a portfolio is priced

Each position is marked from its own price lane and names both the lane and the trading session:

- `markSource: "SettledClose"`, the official end-of-day close, with `markAsOf` naming its session.
- `markSource: "LiveQuote"`, a live reading, used only when it belongs to a **newer** trading day than the settled close. Once the official row for that day is written, the settled close takes over again.
- `markSource: "OptionDailyClose"`, the contract's own daily snapshot, attributed to the session the provider dated it with. `markAsOf: null` means the session is unknown, never today.
- `markSource: null`, meaning the position could not be priced. `markUnavailableReason` says why, and `markPerUnit`, `marketValue` and `unrealizedGain` are all `null`. **No price is never reported as a price of zero**, which would read as a total loss.

`costBasis` covers every open lot, priced or not, because what was paid is always known. `marketValue` and the unrealized figures cover only the priced ones, and `unvaluedPositionCount` is what tells you the totals cover part of the portfolio rather than all of it. `coverageNote` is set when a bound stopped a pass from pricing everything.

A portfolio can also **watch** instruments it does not hold. A watched instrument appears in the valuation's `watching` array with a mark from the same price lanes and nothing else: no quantity, cost or value fields exist on a watch row, and it is never part of `costBasis`, `marketValue` or any gain figure. Watching an instrument you then buy shows one row, not two: the held position appears in `positions` carrying its `watchId`, and `watching` lists only what is not held. A portfolio watches at most 200 instruments.

Percentages are plain numbers: `57.9335` means 57.9335%.


## GET /v1/portfolios

Your portfolios and how many lots each holds. Deliberately unpriced: valuing every portfolio to render a list would fan out to the market data for each one.

**Parameters:** none.

```bash
curl "https://api.equibles.com/v1/portfolios" \
  -H "Authorization: Bearer eq_your_api_key"
```

```python
import requests
r = requests.get(
    "https://api.equibles.com/v1/portfolios",
    headers={"Authorization": "Bearer eq_your_api_key"},
)
print(r.json())
```

```javascript
const res = await fetch("https://api.equibles.com/v1/portfolios", {
  headers: { Authorization: "Bearer eq_your_api_key" },
});
console.log(await res.json());
```

```json
{
  "data": [
    {
      "id": "6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
      "name": "Main",
      "openLotCount": 2,
      "closedLotCount": 1,
      "createdAtUtc": "2026-02-11T09:14:22Z"
    },
    {
      "id": "2d5e0c41-8b77-4a19-93cc-1f6e4a2b8d90",
      "name": "Retirement",
      "openLotCount": 5,
      "closedLotCount": 0,
      "createdAtUtc": "2026-05-30T18:03:41Z"
    }
  ]
}
```

## POST /v1/portfolios

Creates an empty portfolio and returns `201`. The name must be unique among your own and is how the MCP tools address it. A duplicate name, or an eleventh portfolio, returns `400 invalid_parameter` naming the reason.

**Body:** `name` (required, up to 128 characters).

```bash
curl -X POST "https://api.equibles.com/v1/portfolios" \
  -H "Authorization: Bearer eq_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Main"}'
```

```python
import requests
r = requests.post(
    "https://api.equibles.com/v1/portfolios",
    headers={"Authorization": "Bearer eq_your_api_key"},
    json={"name": "Main"},
)
print(r.json())
```

```javascript
const res = await fetch("https://api.equibles.com/v1/portfolios", {
  method: "POST",
  headers: {
    Authorization: "Bearer eq_your_api_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ name: "Main" }),
});
console.log(await res.json());
```

```json
{
  "id": "6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
  "name": "Main",
  "openLotCount": 0,
  "closedLotCount": 0,
  "createdAtUtc": "2026-02-11T09:14:22Z"
}
```

## GET /v1/portfolios/{id}

One portfolio, priced. Open lots are rolled up into a position per instrument, each carrying its own lots; instruments watched but not held come in `watching` with marks only; closed lots are listed separately with their realized result.

**Parameters:** `{id}` (path), a portfolio id from the list above.

```bash
curl "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77" \
  -H "Authorization: Bearer eq_your_api_key"
```

```python
import requests
r = requests.get(
    "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
    headers={"Authorization": "Bearer eq_your_api_key"},
)
print(r.json())
```

```javascript
const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77", {
  headers: { Authorization: "Bearer eq_your_api_key" },
});
console.log(await res.json());
```

```json
{
  "id": "6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
  "name": "Main",
  "asOfUtc": "2026-08-18T17:42:09Z",
  "costBasis": 7220.00,
  "marketValue": 11402.80,
  "unrealizedGain": 4182.80,
  "unrealizedGainPercent": 57.9335,
  "realizedGain": 1043.25,
  "unvaluedPositionCount": 0,
  "coverageNote": null,
  "positions": [
    {
      "instrumentKind": "Stock",
      "ticker": "NVDA",
      "name": "Nvidia Corp",
      "occTicker": null,
      "expirationDate": null,
      "strikePrice": null,
      "contractType": null,
      "sharesPerContract": null,
      "quantity": 40.0,
      "costBasis": 4740.00,
      "averageCostPerUnit": 118.50,
      "markPerUnit": 176.32,
      "markSource": "LiveQuote",
      "markAsOf": "2026-08-18",
      "markUnavailableReason": null,
      "marketValue": 7052.80,
      "unrealizedGain": 2312.80,
      "unrealizedGainPercent": 48.7932,
      "expired": false,
      "lots": [
        {
          "id": "a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411",
          "instrumentKind": "Stock",
          "ticker": "NVDA",
          "name": "Nvidia Corp",
          "occTicker": null,
          "expirationDate": null,
          "strikePrice": null,
          "contractType": null,
          "sharesPerContract": null,
          "quantity": 40.0,
          "costPerUnit": 118.50,
          "costBasis": 4740.00,
          "acquiredDate": "2025-09-02",
          "note": "core position",
          "closedDate": null,
          "closePricePerUnit": null,
          "marketValue": 7052.80,
          "unrealizedGain": 2312.80,
          "realizedGain": null,
          "isOpen": true
        }
      ]
    },
    {
      "instrumentKind": "Option",
      "ticker": "NVDA",
      "name": "Nvidia Corp",
      "occTicker": "O:NVDA270115C00200000",
      "expirationDate": "2027-01-15",
      "strikePrice": 200.0,
      "contractType": "Call",
      "sharesPerContract": 100,
      "quantity": 2.0,
      "costBasis": 2480.00,
      "averageCostPerUnit": 12.40,
      "markPerUnit": 21.75,
      "markSource": "OptionDailyClose",
      "markAsOf": "2026-08-17",
      "markUnavailableReason": null,
      "marketValue": 4350.00,
      "unrealizedGain": 1870.00,
      "unrealizedGainPercent": 75.4032,
      "expired": false,
      "lots": [
        {
          "id": "b7c48e19-2a05-4de3-91f6-3d8a5c1b7e22",
          "instrumentKind": "Option",
          "ticker": "NVDA",
          "name": "Nvidia Corp",
          "occTicker": "O:NVDA270115C00200000",
          "expirationDate": "2027-01-15",
          "strikePrice": 200.0,
          "contractType": "Call",
          "sharesPerContract": 100,
          "quantity": 2.0,
          "costPerUnit": 12.40,
          "costBasis": 2480.00,
          "acquiredDate": "2026-03-17",
          "note": null,
          "closedDate": null,
          "closePricePerUnit": null,
          "marketValue": 4350.00,
          "unrealizedGain": 1870.00,
          "realizedGain": null,
          "isOpen": true
        }
      ]
    }
  ],
  "watching": [
    {
      "id": "d4b90f21-7c3a-4e8f-b6a1-92e5c7d80f34",
      "instrumentKind": "Stock",
      "ticker": "AMD",
      "name": "Advanced Micro Devices Inc",
      "occTicker": null,
      "expirationDate": null,
      "strikePrice": null,
      "contractType": null,
      "sharesPerContract": null,
      "markPerUnit": 172.94,
      "markSource": "SettledClose",
      "markAsOf": "2026-08-17",
      "markUnavailableReason": null,
      "expired": false
    },
    {
      "id": "f8a2c655-1e09-4b7d-a3c8-40d61b9e2a17",
      "instrumentKind": "Option",
      "ticker": "AMD",
      "name": "Advanced Micro Devices Inc",
      "occTicker": "O:AMD270115C00200000",
      "expirationDate": "2027-01-15",
      "strikePrice": 200.0,
      "contractType": "Call",
      "sharesPerContract": 100,
      "markPerUnit": 14.85,
      "markSource": "OptionDailyClose",
      "markAsOf": "2026-08-17",
      "markUnavailableReason": null,
      "expired": false
    }
  ],
  "closedLots": [
    {
      "id": "c92b6f37-5e18-4c74-a0d5-71e93b6a4f08",
      "instrumentKind": "Stock",
      "ticker": "MSFT",
      "name": "Microsoft Corp",
      "occTicker": null,
      "expirationDate": null,
      "strikePrice": null,
      "contractType": null,
      "sharesPerContract": null,
      "quantity": 15.0,
      "costPerUnit": 402.10,
      "costBasis": 6031.50,
      "acquiredDate": "2025-11-04",
      "note": null,
      "closedDate": "2026-06-26",
      "closePricePerUnit": 471.65,
      "marketValue": null,
      "unrealizedGain": null,
      "realizedGain": 1043.25,
      "isOpen": false
    }
  ]
}
```

## POST /v1/portfolios/{id}/lots

Records one purchase or sale and returns `201` with the stored lot.

**Retrying is safe.** An identical request within a few minutes returns the lot that already landed, with `"deduplicated": true` and HTTP `200` instead of `201`, so a retried timeout never leaves you holding the position twice.

**Body:** `ticker` (required; for an option, the underlying), `quantity` (required, signed), `costPerUnit` (required, positive), `acquiredDate` (required, `YYYY-MM-DD`, not in the future), `optionContract` (optional OCC symbol), `note` (optional, up to 256 characters).

```bash
curl -X POST "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots" \
  -H "Authorization: Bearer eq_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"ticker": "NVDA", "optionContract": "O:NVDA270115C00200000", "quantity": 2, "costPerUnit": 12.40, "acquiredDate": "2026-03-17"}'
```

```python
import requests
r = requests.post(
    "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots",
    headers={"Authorization": "Bearer eq_your_api_key"},
    json={
        "ticker": "NVDA",
        "optionContract": "O:NVDA270115C00200000",
        "quantity": 2,
        "costPerUnit": 12.40,
        "acquiredDate": "2026-03-17",
    },
)
print(r.json())
```

```javascript
const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots", {
  method: "POST",
  headers: {
    Authorization: "Bearer eq_your_api_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    ticker: "NVDA",
    optionContract: "O:NVDA270115C00200000",
    quantity: 2,
    costPerUnit: 12.4,
    acquiredDate: "2026-03-17",
  }),
});
console.log(await res.json());
```

```json
{
  "portfolioId": "6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
  "portfolioName": "Main",
  "deduplicated": false,
  "lot": {
    "id": "b7c48e19-2a05-4de3-91f6-3d8a5c1b7e22",
    "instrumentKind": "Option",
    "ticker": "NVDA",
    "name": "Nvidia Corp",
    "occTicker": "O:NVDA270115C00200000",
    "expirationDate": "2027-01-15",
    "strikePrice": 200.0,
    "contractType": "Call",
    "sharesPerContract": 100,
    "quantity": 2.0,
    "costPerUnit": 12.40,
    "costBasis": 2480.00,
    "acquiredDate": "2026-03-17",
    "note": null,
    "closedDate": null,
    "closePricePerUnit": null,
    "marketValue": null,
    "unrealizedGain": null,
    "realizedGain": null,
    "isOpen": true
  }
}
```

A lot returned by a write is unpriced: `marketValue` and `unrealizedGain` are `null` because a write answers about what was recorded, not what it is worth. Fetch the portfolio to have it valued.

## PATCH /v1/portfolios/{id}/lots/{lotId}

Corrects a lot that was entered wrong. Only the fields you send change.

The instrument itself cannot be edited: a lot on the wrong stock or the wrong contract is a different holding, so delete it and add the right one.

**Body:** any of `quantity`, `costPerUnit`, `acquiredDate`, `note`. Send `"note": ""` to clear a note.

```bash
curl -X PATCH "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411" \
  -H "Authorization: Bearer eq_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"costPerUnit": 118.50, "note": "core position"}'
```

```python
import requests
r = requests.patch(
    "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411",
    headers={"Authorization": "Bearer eq_your_api_key"},
    json={"costPerUnit": 118.50, "note": "core position"},
)
print(r.json())
```

```javascript
const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411", {
  method: "PATCH",
  headers: {
    Authorization: "Bearer eq_your_api_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ costPerUnit: 118.5, note: "core position" }),
});
console.log(await res.json());
```

```json
{
  "portfolioId": "6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
  "portfolioName": "Main",
  "deduplicated": false,
  "lot": {
    "id": "a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411",
    "instrumentKind": "Stock",
    "ticker": "NVDA",
    "name": "Nvidia Corp",
    "occTicker": null,
    "expirationDate": null,
    "strikePrice": null,
    "contractType": null,
    "sharesPerContract": null,
    "quantity": 40.0,
    "costPerUnit": 118.50,
    "costBasis": 4740.00,
    "acquiredDate": "2025-09-02",
    "note": "core position",
    "closedDate": null,
    "closePricePerUnit": null,
    "marketValue": null,
    "unrealizedGain": null,
    "realizedGain": null,
    "isOpen": true
  }
}
```

## POST /v1/portfolios/{id}/lots/{lotId}/close

Records a sale. Omit `quantity` to close the whole lot, or pass less to close part of it. A partial close splits the lot, so the returned closed lot carries its **own** id and the remainder stays open on the original cost basis.

**Body:** `closePricePerUnit` (required, positive), `closeDate` (required, `YYYY-MM-DD`, not before the lot was acquired), `quantity` (optional, unsigned).

```bash
curl -X POST "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411/close" \
  -H "Authorization: Bearer eq_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"closePricePerUnit": 471.65, "closeDate": "2026-06-26"}'
```

```python
import requests
r = requests.post(
    "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411/close",
    headers={"Authorization": "Bearer eq_your_api_key"},
    json={"closePricePerUnit": 471.65, "closeDate": "2026-06-26"},
)
print(r.json())
```

```javascript
const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411/close", {
  method: "POST",
  headers: {
    Authorization: "Bearer eq_your_api_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ closePricePerUnit: 471.65, closeDate: "2026-06-26" }),
});
console.log(await res.json());
```

```json
{
  "portfolioId": "6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
  "portfolioName": "Main",
  "deduplicated": false,
  "lot": {
    "id": "c92b6f37-5e18-4c74-a0d5-71e93b6a4f08",
    "instrumentKind": "Stock",
    "ticker": "MSFT",
    "name": "Microsoft Corp",
    "occTicker": null,
    "expirationDate": null,
    "strikePrice": null,
    "contractType": null,
    "sharesPerContract": null,
    "quantity": 15.0,
    "costPerUnit": 402.10,
    "costBasis": 6031.50,
    "acquiredDate": "2025-11-04",
    "note": null,
    "closedDate": "2026-06-26",
    "closePricePerUnit": 471.65,
    "marketValue": null,
    "unrealizedGain": null,
    "realizedGain": 1043.25,
    "isOpen": false
  }
}
```

## DELETE /v1/portfolios/{id}/lots/{lotId}

Removes a lot as though it had never been recorded, for something entered by mistake. A sale is recorded by closing the lot instead, which keeps its realized profit and loss. Returns `204` with no body, and cannot be undone.

```bash
curl -X DELETE "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/b7c48e19-2a05-4de3-91f6-3d8a5c1b7e22" \
  -H "Authorization: Bearer eq_your_api_key"
```

```python
import requests
r = requests.delete(
    "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/b7c48e19-2a05-4de3-91f6-3d8a5c1b7e22",
    headers={"Authorization": "Bearer eq_your_api_key"},
)
print(r.status_code)
```

```javascript
const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/b7c48e19-2a05-4de3-91f6-3d8a5c1b7e22", {
  method: "DELETE",
  headers: { Authorization: "Bearer eq_your_api_key" },
});
console.log(res.status);
```

## POST /v1/portfolios/{id}/watches

Puts an instrument on the portfolio's watchlist without recording any position, and returns `201` with the stored watch row. Pass `optionContract` with the OCC symbol to watch an option, or omit it to watch the stock. The instrument is verified against the live reference data before anything is stored, exactly like a lot's, so an unknown ticker or contract is rejected rather than saved. Watching an instrument the portfolio already watches returns `400 invalid_parameter` saying so.

The write answers with identity only; the mark fields fill in on the priced `GET`, which lists the row in `watching`.

**Body:** `ticker` (required; for an option, the underlying's ticker), `optionContract` (optional OCC symbol).

```bash
curl -X POST "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/watches" \
  -H "Authorization: Bearer eq_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"ticker": "AMD"}'
```

```python
import requests
r = requests.post(
    "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/watches",
    headers={"Authorization": "Bearer eq_your_api_key"},
    json={"ticker": "AMD"},
)
print(r.json())
```

```javascript
const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/watches", {
  method: "POST",
  headers: {
    Authorization: "Bearer eq_your_api_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ ticker: "AMD" }),
});
console.log(await res.json());
```

```json
{
  "portfolioId": "6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
  "portfolioName": "Main",
  "watch": {
    "id": "d4b90f21-7c3a-4e8f-b6a1-92e5c7d80f34",
    "instrumentKind": "Stock",
    "ticker": "AMD",
    "name": "Advanced Micro Devices Inc",
    "occTicker": null,
    "expirationDate": null,
    "strikePrice": null,
    "contractType": null,
    "sharesPerContract": null,
    "markPerUnit": null,
    "markSource": null,
    "markAsOf": null,
    "markUnavailableReason": null,
    "expired": false
  }
}
```

To watch an option instead, name the contract alongside its underlying, the same pair the lot endpoint takes: `{"ticker": "AMD", "optionContract": "O:AMD270115C00200000"}`. A contract with no published contract size is still watchable — a watch row has no economics for the multiplier to compute — though it could not be held as a lot.

## DELETE /v1/portfolios/{id}/watches/{watchId}

Stops watching an instrument. Removes only the watch row — any lots on the same instrument are untouched. Returns `204` with no body. The `{watchId}` comes from the valuation's `watching` array, or from the answer to the `POST` above.

```bash
curl -X DELETE "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/watches/d4b90f21-7c3a-4e8f-b6a1-92e5c7d80f34" \
  -H "Authorization: Bearer eq_your_api_key"
```

```python
import requests
r = requests.delete(
    "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/watches/d4b90f21-7c3a-4e8f-b6a1-92e5c7d80f34",
    headers={"Authorization": "Bearer eq_your_api_key"},
)
print(r.status_code)
```

```javascript
const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/watches/d4b90f21-7c3a-4e8f-b6a1-92e5c7d80f34", {
  method: "DELETE",
  headers: { Authorization: "Bearer eq_your_api_key" },
});
console.log(res.status);
```

## DELETE /v1/portfolios/{id}

Deletes a portfolio and every lot in it, including the closed ones and their realized history. Returns `204` with no body, and cannot be undone.

```bash
curl -X DELETE "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77" \
  -H "Authorization: Bearer eq_your_api_key"
```

```python
import requests
r = requests.delete(
    "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
    headers={"Authorization": "Bearer eq_your_api_key"},
)
print(r.status_code)
```

```javascript
const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77", {
  method: "DELETE",
  headers: { Authorization: "Bearer eq_your_api_key" },
});
console.log(res.status);
```

## Privacy

A portfolio is yours. It is stored against your account, it is never used to build market data or any public dataset, and it is never shown to another account. Deleting a portfolio deletes its lots with it.