The Sensible Trader
REST API
Add trades to your journal programmatically — from scripts, spreadsheets, automations (n8n, Zapier, Make), or any custom tooling. Authentication uses an API key you generate inside the app.
https://api.the-sensible-trader.com/api
Authentication #
All API requests must include your API key in the x-api-key request header. Keys are generated per-user inside the app and grant write access to your trade journal.
Generating a key
Log into me.the-sensible-trader.com, open Settings → API tokens, enter a name for the key, and click Generate key. The full key is shown exactly once — copy it immediately.
POST https://api.the-sensible-trader.com/api/v1/trades x-api-key: st_your_api_key_here Content-Type: application/json
Base URL #
All endpoints are relative to the base URL below. Currently only v1 is available.
https://api.the-sensible-trader.com/api
All requests and responses use application/json.
Rate limits #
The API enforces per-IP and per-user limits to protect service quality.
| Limit | Value | Scope |
|---|---|---|
| Requests / minute | 100 | Per IP address |
| AI parses / day | 20 | Per user (screenshot parsing only — not the trades API) |
| AI parses / month | 500 | Per user (screenshot parsing only) |
When a rate limit is exceeded the API returns 429 Too Many Requests or 403 Forbidden.
GET /v1/trades #
Returns a paginated list of trades in your journal. Supports filtering by status, strategy, ticker, date window, duration, P&L, and more. All filters are combinable.
GET https://api.the-sensible-trader.com/api/v1/trades
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| page | integer | 1 | Page number (1-based). |
| limit | integer | 20 | Results per page. Max 200. |
| status | string | — | open · closed · expired. Omit for all trades. |
| strategy | string | — | Filter by strategy: CSP CC Long Call Long Put Naked Call Debit Spread Credit Spread Iron Condor Butterfly Shares. |
| ticker | string | — | Case-insensitive symbol match, e.g. NVDA. Partial match supported. |
| broker | string | — | Filter by broker platform. Exact match — use the same value as brokerPlatform on POST: Robinhood Merrill Edge tastytrade Charles Schwab Fidelity ETrade IBKR Webull TD Ameritrade. |
| sector | string | — | Filter by sector, e.g. Technology Healthcare Energy. Use Other for tickers not in the built-in sector map. |
| search | string | — | Full-text search across ticker and comments. |
| dateFrom | string | — | ISO 8601 date — only trades opened on or after this date. e.g. 2025-01-01. |
| dateTo | string | — | ISO 8601 date — only trades opened on or before this date. |
| durationMin | integer | — | Minimum trade duration in days (close date − open date). Applies to closed trades only. |
| durationMax | integer | — | Maximum trade duration in days. |
| minPnl | number | — | Minimum realized P&L in dollars (e.g. 500 for ≥ $500). |
| maxPnl | number | — | Maximum realized P&L in dollars. |
| winOnly | boolean | false | Set true to return only profitable closed trades (realizedPnL > 0). |
| lossOnly | boolean | false | Set true to return only losing closed trades (realizedPnL < 0). |
| sortBy | string | dateOpened | Field to sort by: dateOpened dateClosed realizedPnL ticker expiration. |
| sortDir | string | desc | asc or desc. |
Response
Returns 200 OK with a JSON object:
{
"trades": [/* Trade objects — same shape as POST response */],
"total": 42, // trades matching the current status tab + filters
"page": 1,
"limit": 20,
"totalPages": 3,
"allCount": 118, // all trades matching filters (ignoring status tab)
"openCount": 12,
"closedCount": 98,
"expiredCount":8,
"filteredPnL": 18432.50, // realized P&L across all matched closed trades
"filteredWinRate": 87.5 // win rate % across matched closed trades
}
Example
curl "https://api.the-sensible-trader.com/api/v1/trades?status=closed&strategy=CSP&dateFrom=2025-01-01&dateTo=2025-06-30&durationMin=7&durationMax=45&winOnly=true&limit=50" \ -H "x-api-key: YOUR_API_KEY"
POST /v1/trades #
Creates a new trade in your journal. Supports all trade types: options (CSP, CC, Long Call, Long Put, spreads), shares, and multi-leg strategies.
Parameters
Send parameters as a JSON body with Content-Type: application/json.
| Name | Type | Required | Description |
|---|---|---|---|
| ticker | string | Required | Stock or ETF ticker symbol. Automatically uppercased. AAPLTSLASPY |
| tradeStrategy | string | Required | The strategy used for this position. Must be one of the supported values.
CSPCCLong CallLong Put
SharesNaked CallDebit Spread
Credit SpreadIron CondorButterfly
|
| action | string | Required | The trade action. Opening actions create new positions; closing actions mark a position closed.
BTOSTOBTCSTC
BUYSELLEXPASN
See Strategies & actions for the valid pairings.
|
| brokerPlatform | string | Required | Broker or platform where the trade was executed.
RobinhoodMerrill Edgetastytrade
Charles SchwabFidelityETrade
IBKRWebullTD AmeritradeOther
|
| contracts | number | Required | Number of contracts (options) or shares (for the Shares strategy). Must be ≥ 1. |
| dateOpened | string | Required | Date the position was opened. Accepts YYYY-MM-DD or a full ISO 8601 datetime with timezone offset (e.g. 2026-08-13T14:30:00-04:00). Providing a time enables accurate price-action episode generation. |
| openPrice | number | Required | Per-share/contract price at which the position was opened (premium collected or paid). |
| strike | number | Optional | Strike price for options. Required for all options strategies; omit for Shares. |
| expiration | string | Optional | Option expiration date in YYYY-MM-DD format. Recommended for all options positions. |
| dateClosed | string | Optional | Date the position was closed. Accepts YYYY-MM-DD or a full ISO 8601 datetime with timezone offset (e.g. 2026-08-13T15:15:00-04:00). Include to log a fully closed trade in a single call. |
| closedPrice | number | Optional | Per-share/contract price at which the position was closed. Required if dateClosed is provided. |
| isExpired | boolean | Optional | Set to true if the option expired worthless. Defaults to false. |
| comments | string | Optional | Free-text notes for this trade. Supports up to 2,000 characters. |
| reviewFlag | boolean | Optional | Mark this trade for manual review in the app. Useful when logging from automation and some fields are uncertain. |
| tags | string[] | Optional | Array of custom string tags for filtering and grouping trades. |
| targetProfitPct | number | Optional | Target profit as a percentage of max profit (e.g. 50 for 50%). Used to calculate a profit target line on charts. |
| targetLossPct | number | Optional | Maximum acceptable loss as a percentage (e.g. 100 for full premium at risk). Used to calculate a stop-loss line on charts. |
| legs | object[] | Optional | Array of leg objects for multi-leg strategies (spreads, iron condors, butterflies). Each leg has: action (BTO/STO), optionType (Call/Put), strike, openPrice, role (e.g. long/short), contractMultiplier (typically 100). Optionally closePrice when closing. |
Strategies & actions
Each strategy has a fixed set of valid opening and closing actions. Mismatched combinations are rejected with a validation error.
| Strategy | Open action | Close action | Notes |
|---|---|---|---|
| CSP | STO | BTC | Cash-secured put — sell to open, buy to close |
| CC | STO | BTC | Covered call — sell to open, buy to close |
| Long Call | BTO | STC | Buy to open, sell to close |
| Long Put | BTO | STC | Buy to open, sell to close |
| Shares | BUY | SELL | Use contracts for share quantity |
| Credit Spread | STO | BTC | Use legs array for individual legs |
| Debit Spread | BTO | STC | Use legs array for individual legs |
| Iron Condor | STO | BTC | Use legs for all 4 legs |
| Butterfly | STO / BTO | BTC / STC | Credit butterfly: STO/BTC. Debit butterfly: BTO/STC. Use legs for all legs. |
| Naked Call | STO | BTC | Sell to open, buy to close |
| Any | — | EXP / ASN | EXP = expired worthless · ASN = assigned |
Responses
On success the full trade object is returned:
{
"_id": "685312abc1234def56789012",
"ticker": "AAPL",
"tradeStrategy": "CSP",
"action": "STO",
"brokerPlatform": "Robinhood",
"contracts": 1,
"strike": 170,
"dateOpened": "2026-06-08T14:30:00.000Z",
"expiration": "2026-06-20",
"openPrice": 2.5,
"closedPrice": null,
"dateClosed": null,
"isOpen": true,
"isExpired": false,
"reviewFlag": false,
"comments": null,
"tags": [],
"legs": [],
"targetProfitPct": null,
"targetLossPct": null,
// Computed fields — derived server-side, read-only
"status": "open", // "open" | "closed" | "expired"
"totalPremium": 250, // openPrice × contracts × 100
"capitalAtRisk": 17000, // strike × contracts × 100 (for puts)
"realizedPnL": null, // computed on close: (openPrice − closedPrice) × contracts × 100
"roci": null, // return on capital invested (%)
"daysHeld": null, // dateClosed − dateOpened in days
"createdAt": "2026-06-08T18:32:11.000Z"
}
DELETE /v1/trades/:id #
Permanently delete a trade by its _id. The trade must belong to the authenticated user — attempts to delete another user's trade return 404.
DELETE https://api.the-sensible-trader.com/api/v1/trades/:id x-api-key: st_your_api_key_here
Path parameter
| Name | Type | Required | Description |
|---|---|---|---|
| id | string | Required | The MongoDB _id of the trade to delete. Returned as _id in the GET and POST responses. |
Responses
On success the server returns 204 No Content with an empty body.
Example
curl -X DELETE \ https://api.the-sensible-trader.com/api/v1/trades/685312abc1234def56789012 \ -H "x-api-key: st_your_api_key_here"
const tradeId = '685312abc1234def56789012'; const res = await fetch( `https://api.the-sensible-trader.com/api/v1/trades/${tradeId}`, { method: 'DELETE', headers: { 'x-api-key': 'st_your_api_key_here' }, } ); // 204 = deleted; 404 = not found or not yours if (res.ok) console.log('Trade deleted');
Example: Cash-secured put #
Sell to open a CSP on AAPL with a $170 strike expiring June 20.
curl -X POST https://api.the-sensible-trader.com/api/v1/trades \ -H "x-api-key: st_your_api_key_here" \ -H "Content-Type: application/json" \ -d '{ "ticker": "AAPL", "tradeStrategy": "CSP", "action": "STO", "brokerPlatform": "Robinhood", "contracts": 1, "strike": 170, "dateOpened": "2026-06-08", "expiration": "2026-06-20", "openPrice": 2.50 }'
Example: Covered call #
Sell to open a covered call on TSLA with a $350 strike.
curl -X POST https://api.the-sensible-trader.com/api/v1/trades \ -H "x-api-key: st_your_api_key_here" \ -H "Content-Type: application/json" \ -d '{ "ticker": "TSLA", "tradeStrategy": "CC", "action": "STO", "brokerPlatform": "Merrill Edge", "contracts": 2, "strike": 350, "dateOpened": "2026-06-08", "expiration": "2026-06-27", "openPrice": 4.20, "comments": "Selling against 200 shares held" }'
Example: Long call / put #
Buy to open a long call on NVDA.
curl -X POST https://api.the-sensible-trader.com/api/v1/trades \ -H "x-api-key: st_your_api_key_here" \ -H "Content-Type: application/json" \ -d '{ "ticker": "NVDA", "tradeStrategy": "Long Call", "action": "BTO", "brokerPlatform": "tastytrade", "contracts": 3, "strike": 130, "dateOpened": "2026-06-08", "expiration": "2026-07-18", "openPrice": 8.75 }'
Example: Closing a trade #
To log an already-closed position in one call, include dateClosed and closedPrice. The app will compute realized P&L automatically.
curl -X POST https://api.the-sensible-trader.com/api/v1/trades \ -H "x-api-key: st_your_api_key_here" \ -H "Content-Type: application/json" \ -d '{ "ticker": "CRWD", "tradeStrategy": "CSP", "action": "BTC", "brokerPlatform": "Merrill Edge", "contracts": 3, "strike": 670, "dateOpened": "2026-06-04", "expiration": "2026-06-05", "openPrice": 3.40, "dateClosed": "2026-06-05", "closedPrice": 0.30 }'
Error codes #
All errors return JSON with a message, error, and statusCode field.
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Invalid or revoked API key"
}
Client libraries #
The API is plain HTTP+JSON — use any HTTP client. Here are quick-start snippets for the most common environments.
JavaScript / Node.js
// Works in Node.js 18+ (native fetch) and modern browsers const res = await fetch( 'https://api.the-sensible-trader.com/api/v1/trades', { method: 'POST', headers: { 'x-api-key': 'st_your_api_key_here', 'Content-Type': 'application/json', }, body: JSON.stringify({ ticker: 'AAPL', tradeStrategy: 'CSP', action: 'STO', brokerPlatform: 'Robinhood', contracts: 1, strike: 170, dateOpened: '2026-06-08', expiration: '2026-06-20', openPrice: 2.50, }), } ); const trade = await res.json(); console.log(trade._id);
Python
import requests
res = requests.post(
"https://api.the-sensible-trader.com/api/v1/trades",
headers={
"x-api-key": "st_your_api_key_here",
"Content-Type": "application/json",
},
json={
"ticker": "AAPL",
"tradeStrategy": "CSP",
"action": "STO",
"brokerPlatform": "Robinhood",
"contracts": 1,
"strike": 170,
"dateOpened": "2026-06-08",
"expiration": "2026-06-20",
"openPrice": 2.50,
},
)
res.raise_for_status()
print(res.json()["_id"])