CoveredLoop exposes an HTTP API for member integrations (personal access tokens), uptime probes, authentication, mobile-store billing hooks, and scheduled operations. The member surface covers the dashboard, reports, watch lists, alerts, Profit & Loss, Metrics, portfolio, holdings, and trades. Live Tradier trading covers stock, single options, covered combos, rolls, credit spreads, flatten/close, and cancel or change of a working order. Every write defaults to dry-run. First-party product screens also run as authenticated TanStack Start server functions inside the web app.
Version 2026.09.26.2 · Updated September 26, 2026 · Base URL https://coveredloop.com
v2026.09.26.2 · September 26, 2026. Same list is in the branded PDF.
Account-scoped personal access tokens (clp_…); bots can connect with a short code instead of a pasted key
Dashboard summary bubbles — full grant and per account
Flatten / close, open, roll, and change Live Tradier orders — dry-run unless confirm=true
Reports generator — JSON, PDF, Excel, and Word (same as /app/reports)
Watch lists, price alerts, and trade-alert preferences
Profit & Loss calendar (day / month / opened) and Metrics groups
Conventions
Rules every integration should follow.
Send JSON bodies as application/json. Successful responses are JSON objects.
Errors use { "error": "message" } and an HTTP 4xx/5xx status.
Authorization for server-to-server calls is Authorization: Bearer <secret>. Never put secrets in query strings in production.
Members create a personal access token in Settings → API and send Authorization: Bearer clp_…. Tokens are read-only unless you enable trade scope at mint time. Optionally pin the token to specific accounts so a third-party app cannot see the rest of the book. GET /api/v1/dashboard, /reports, /portfolio, /pl/*, /metrics, /positions, and /orders honor that pin. Watch lists and price alerts are member-level. POST /api/v1/orders, /api/v1/orders/cancel, /api/v1/orders/change, and /api/v1/positions/flatten require trade scope, default to dry-run, and only send to Tradier when dryRun=false and confirm=true.
Browser sign-in uses same-origin cookies on /api/auth/*. Preview / native clients may attach the Better Auth bearer token instead.
Rate limits apply to auth and admin mutations. Retry 429s with backoff.
All timestamps are ISO-8601 UTC unless noted.
Secrets
Set these in the host environment. Values are never returned by the API.
Variable
Used by
CRON_SECRET
All /api/cron/* routes
HEALTH_DETAIL_SECRET
Unused by public /api/health. Owner diagnostics use an Owner session or Owner API token on GET /api/health/deep.
STORE_WEBHOOK_SECRET
POST /api/billing/store-notify (required; not CRON_SECRET)
DEV_VERIFY_SECRET
POST /api/dev/verify-email (required; localhost only)
Health & uptime
Lightweight probe for external monitors (Better Stack, UptimeRobot). Keyword match on "ok":true or "status":"up". Poll every 1–5 minutes.
GET
Public health probe
/api/health
Public
Liveness only. No broker, rebuild, or portfolio fields. Always HTTP 200 with ok, status, version, and time when the process is up. Poll every 1–5 minutes. A signed-in account owner receives diagnostics on this same path; everyone else does not.
Broker, rebuild, day tiles, and dependency checks. Same report as GET /api/health when the caller is the account owner. Regular members, non-owner administrators, and unsigned callers receive only the public liveness body.
Auth: Owner session cookie, or Authorization: Bearer clp_… minted for the account owner
Without an Owner session or Owner API token the public liveness payload is returned (no 401, no broker or rebuild fields). 503 when the owner dependency check finds the database down.
Member accounts run through Better Auth at /api/auth/*. Browser clients use same-origin session cookies. Native or preview clients may send Authorization: Bearer <session token>. Email must be verified before full product access. MFA (TOTP) is supported.
POST
Create account
/api/auth/sign-up/email
Member session
Registers an email/password member. A verification email is sent. Session may be created pending verification.
Creates a session cookie. If MFA is enabled the payload includes twoFactorRedirect: true and the client must complete /api/auth/two-factor/verify-totp.
Auth: None
Name
In
Required
Type
Description
email
body
Yes
string
Account email.
password
body
Yes
string
Account password.
callbackURL
body
No
string
Post-login path for browser clients.
Success
{ "user": { "id": "...", "email": "..." }, "token": "..." }
// or { "twoFactorRedirect": true } when MFA is on
Errors
401 invalid credentials; 403 email not verified; 429 rate-limited.
Two ways to get a token. (1) Personal access token: mint it in Settings → API → Advanced and store it on the machine that calls the API. Use this when a chat assistant is only helping you set up a script. Do not paste the token into a chat, and the assistant must not call /api/v1/connect or take the token. (2) Bot connection: only when the bot itself will call CoveredLoop and can store the key in its own runtime. POST /api/v1/connect {"action":"start","name":"<program name>"}, the user approves the short code in Settings → API, then the bot polls {"action":"poll","device_code":"..."} and stores the Bearer token outside the chat. An existing token keeps working. Optionally limit the token to specific accounts (Tradier Live, Paper, Manual, or Sample). Send Authorization: Bearer clp_… on every request. Copy the full key anytime from the token list while signed in (encrypted at rest). Tokens are hashed for lookup. Default scope is read. Enable trade when minting to buy and sell stock and options, place covered calls, buy-writes, rolls, and spreads, flatten an open position, and cancel or change a working order. Dry-run is the default. A live place, cancel, or change still requires dryRun=false and confirm=true. They do not grant admin, another user's data, or accounts you did not pin. Existing tokens with no account list keep access to every current and future account. Pass ?account=<id> on book endpoints to further filter within the grant. GET /api/v1/dashboard returns the dashboard summary bubbles for the full grant and per account. GET /api/v1/reports generates the same PDF / Excel / Word / JSON report as the Reports page. Profit & Loss and Metrics match the in-app Calendar and Metrics pages (token-scoped accounts, not the dashboard book selector). Watch lists and price alerts are member-level (not brokerage-account rows); trade-alert preferences are filtered to the token's granted accounts.
POST
Start a bot connection
/api/v1/connect
Public
No access token. Only the program that will call CoveredLoop and store the key itself should start this. A chat that is helping someone install a local script must not call it. The caller names itself and receives a short user_code for the person and a device_code it keeps. The code expires in 10 minutes.
Auth: None
Name
In
Required
Type
Description
action
body
Yes
string
Send "start".
name
body
Yes
string
Name of the program that will call the API and store the token. At least 2 characters. Not the name of a chat assistant unless that assistant is the API client.
No access token. Poll about every 5 seconds from the same program that started the connection. Pending until the user approves. Approved returns the Bearer token once; store it outside the chat. An existing clp_ token is not affected. A chat that is only helping the user set up a local script must not poll.
Auth: None
Name
In
Required
Type
Description
action
body
Yes
string
Send "poll".
device_code
body
Yes
string
The device_code from the start call. Do not show this to the user.
Active data mode, selected accounts, summary, returns, holdings, trades, covered calls, and credit spreads. Scoped to the token's granted accounts (or the dashboard book if the token is unrestricted). Other accounts are omitted.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
Every summary tile on /app: equity / cash / buying potential / encumbered cash / open investments / Day P&L / overnight / overnight+session / account fees (commissions, margin interest, subscription, other) / open positions / net transfers, the chart-range P&L row (realized, unrealized, current unrealized, trading costs as commissions only, wheel premium, credit-spread premium), and Bal + TWR returns. Top-level objects are the combined granted book. accounts[] repeats the summary and P&L tiles per brokerage account using the same fee calculation as that account alone, so the account-fee rows add up to the combined tile. Pass ?account= to load one account only (combined then matches that row). P&L tiles follow ?range= (same windows as the dashboard chart; default 1D). Read tokens stay read-only.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
range
query
No
1D | 1W | 1M | 3M | 6M | YTD | 1Y | ALL
Window for the P&L bubbles (realized / unrealized / premiums). Default 1D, matching the dashboard chart. Session tiles (Day P&L, overnight) are always today and ignore this.
import os, requests
r = requests.get(
"https://coveredloop.com/api/v1/dashboard",
params={"range": "1M"},
headers={"Authorization": f"Bearer {os.environ['COVEREDLOOP_TOKEN']}"},
timeout=30,
)
book = r.json()
print(book["summary"])
for acct in book["accounts"]:
print(acct["id"], acct["summary"])
GET
Generate a report
/api/v1/reports
Member session
Same generator as Reports in the app. Default format=json returns the executive summary, score, metrics, and optional trade list. Pass format=pdf|xlsx|docx to download the branded file (PDF/Word skip in-app charts because those need a browser canvas; Excel is complete). Filters match the Reports page: date range, status, symbols, trade types, unrealized, min P&L. Token-scoped. Pass ?account= to generate for one granted account, or ?accounts=id1,id2 to further limit within the grant.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
format
query
No
json | pdf | xlsx | docx
json (default) for a payload; pdf / xlsx / docx for a file download.
from
query
No
YYYY-MM-DD
Range start (inclusive). Defaults to the first trade (capped at about four years).
to
query
No
YYYY-MM-DD
Range end (inclusive). Defaults to today.
status
query
No
open | closed
Comma-separated. Default both.
symbol
query
No
string
Comma-separated symbols / underlyings. Empty = all.
Asks the server to pull this user's Tradier books and waits for that run. Read-only tokens may call it. It never places an order. At most one new run per user per 60 seconds. A run already in progress is returned instead of starting another.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token. Read-only tokens are allowed.
Research watch lists for the token owner (id, name, symbol count, symbols). Same lists as Research → Watch lists and Alerts. Member-level — not filtered by the token's brokerage account pin.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
Stock, ETF, and option price alerts for the token owner (same rows as /app/alerts). Filter by status, symbol, or unread triggered notices. Member-level — not filtered by brokerage account pin.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
status
query
No
active | triggered | dismissed
Filter by alert status.
symbol
query
No
string
Underlying or OCC option symbol (case-insensitive).
unread
query
No
0 | 1
If 1, only triggered alerts that have not been dismissed/seen in-app.
Email preferences for option expiration, ITM/OTM crosses, and uncovered-share notices (Settings → Alerts). accountIds is intersected with the token grant; an empty stored list means every granted account.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
Same figures as Profit and Loss → Calendar. Each day includes realized P&L on the close date, unrealized level and day change, trades opened that day, and how many positions were still open. Compact trade lists are included unless details=0. Pass positions=1 to attach still-open mark-to-market rows on every day (large). Realized is close-to-close; overnight is a slice of that, not a second total.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
book
query
No
sample | manual | live | paper
Limit to one Profit & Loss book. If omitted, defaults to live when that book is in the grant (otherwise sample, then manual, then paper). Sample and manual are never combined with live or paper.
from
query
No
YYYY-MM-DD
Range start (inclusive). Defaults to the first trade (capped at about four years).
to
query
No
YYYY-MM-DD
Range end (inclusive). Defaults to today.
details
query
No
0 | 1
Include compact trade lists. Calendar and opened default on; months, summary, and distribution default off.
positions
query
No
0 | 1
Include still-open positions with unrealized level/change on each day. Default off — use /api/v1/pl/day for one date.
Full breakdown for a single YYYY-MM-DD: realized closes, trades opened that day, and every position that was still open with unrealized level and change vs the prior day.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
book
query
No
sample | manual | live | paper
Limit to one Profit & Loss book. If omitted, defaults to live when that book is in the grant (otherwise sample, then manual, then paper). Sample and manual are never combined with live or paper.
One row per YYYY-MM: realized P&L, win/loss counts, trades opened that month, unrealized level at month-end and change during the month, plus long vs short slices. Pass details=1 for compact closed trades.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
book
query
No
sample | manual | live | paper
Limit to one Profit & Loss book. If omitted, defaults to live when that book is in the grant (otherwise sample, then manual, then paper). Sample and manual are never combined with live or paper.
from
query
No
YYYY-MM-DD
Range start (inclusive). Defaults to the first trade (capped at about four years).
to
query
No
YYYY-MM-DD
Range end (inclusive). Defaults to today.
details
query
No
0 | 1
Include compact trade lists. Calendar and opened default on; months, summary, and distribution default off.
Structures opened on each day in the range (covered-call / spread legs collapsed the same way as the Calendar opened overlay).
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
book
query
No
sample | manual | live | paper
Limit to one Profit & Loss book. If omitted, defaults to live when that book is in the grant (otherwise sample, then manual, then paper). Sample and manual are never combined with live or paper.
from
query
No
YYYY-MM-DD
Range start (inclusive). Defaults to the first trade (capped at about four years).
Long vs short realized and unrealized for a date range — the Summary tab in Profit and Loss.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
book
query
No
sample | manual | live | paper
Limit to one Profit & Loss book. If omitted, defaults to live when that book is in the grant (otherwise sample, then manual, then paper). Sample and manual are never combined with live or paper.
from
query
No
YYYY-MM-DD
Range start (inclusive). Defaults to the first trade (capped at about four years).
to
query
No
YYYY-MM-DD
Range end (inclusive). Defaults to today.
details
query
No
0 | 1
Include compact trade lists. Calendar and opened default on; months, summary, and distribution default off.
Closed-trade P&L buckets matching Profit and Loss → Distribution. Dimension: symbol, strategy, sector, weekday, account, month, or year.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
book
query
No
sample | manual | live | paper
Limit to one Profit & Loss book. If omitted, defaults to live when that book is in the grant (otherwise sample, then manual, then paper). Sample and manual are never combined with live or paper.
from
query
No
YYYY-MM-DD
Range start (inclusive). Defaults to the first trade (capped at about four years).
to
query
No
YYYY-MM-DD
Range end (inclusive). Defaults to today.
details
query
No
0 | 1
Include compact trade lists. Calendar and opened default on; months, summary, and distribution default off.
dimension
query
No
symbol | strategy | sector | weekday | account | month | year
Realized bars and unrealized level/change for the Chart tab. Grain: day, week, month (default), or year.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
book
query
No
sample | manual | live | paper
Limit to one Profit & Loss book. If omitted, defaults to live when that book is in the grant (otherwise sample, then manual, then paper). Sample and manual are never combined with live or paper.
from
query
No
YYYY-MM-DD
Range start (inclusive). Defaults to the first trade (capped at about four years).
Every Metrics-page number: summary tiles plus trade, quality, and risk groups. Same formulas as /app/metrics for the token's accounts.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
book
query
No
sample | manual | live | paper
Limit to one Profit & Loss book. If omitted, defaults to live when that book is in the grant (otherwise sample, then manual, then paper). Sample and manual are never combined with live or paper.
details
query
No
1
Pass details=1 to include structures: one row per closed structure counted in this response (account id, structure id, kind, underlying, open and close dates, realized P&L, member leg and trade ids). The combined list is the union of the per-account lists. Same rule on every account.
Closed trades, winners/losers, win rate, net equity P&L, and max drawdown (peak/trough dates and dollars).
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
book
query
No
sample | manual | live | paper
Limit to one Profit & Loss book. If omitted, defaults to live when that book is in the grant (otherwise sample, then manual, then paper). Sample and manual are never combined with live or paper.
details
query
No
1
Pass details=1 to include structures: one row per closed structure counted in this response (account id, structure id, kind, underlying, open and close dates, realized P&L, member leg and trade ids). The combined list is the union of the per-account lists. Same rule on every account.
Win/loss ratio, average trade P&L, profit factor, average P&L %, winning/losing %, and trade counts.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
book
query
No
sample | manual | live | paper
Limit to one Profit & Loss book. If omitted, defaults to live when that book is in the grant (otherwise sample, then manual, then paper). Sample and manual are never combined with live or paper.
details
query
No
1
Pass details=1 to include structures: one row per closed structure counted in this response (account id, structure id, kind, underlying, open and close dates, realized P&L, member leg and trade ids). The combined list is the union of the per-account lists. Same rule on every account.
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
book
query
No
sample | manual | live | paper
Limit to one Profit & Loss book. If omitted, defaults to live when that book is in the grant (otherwise sample, then manual, then paper). Sample and manual are never combined with live or paper.
details
query
No
1
Pass details=1 to include structures: one row per closed structure counted in this response (account id, structure id, kind, underlying, open and close dates, realized P&L, member leg and trade ids). The combined list is the union of the per-account lists. Same rule on every account.
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
book
query
No
sample | manual | live | paper
Limit to one Profit & Loss book. If omitted, defaults to live when that book is in the grant (otherwise sample, then manual, then paper). Sample and manual are never combined with live or paper.
details
query
No
1
Pass details=1 to include structures: one row per closed structure counted in this response (account id, structure id, kind, underlying, open and close dates, realized P&L, member leg and trade ids). The combined list is the union of the per-account lists. Same rule on every account.
Every Live trading action in the app is available here: buy or sell stock, open or close a single option (covered call, cash-secured put, or a leftover leg), buy-write or close a covered call as one combo, roll an option, open or close a credit spread (2–4 legs), flatten an existing structure, and cancel or change a working order. Tokens default to read. Mint a token with trade scope in Settings → API. Dry-run is the default on every write: omit dryRun, or send dryRun=true / preview=true, and nothing is sent to the book (new orders still ask Tradier for a preview of cost and buying power). A live place, cancel, or change requires all three: trade scope, dryRun=false, and confirm=true. Sample and manual books are not tradable. The account must be on the token grant and on the linked Tradier profile.
GET
Open multi-leg positions
/api/v1/positions
Member session
Flattenable covered-call / wheel / CSP structures and credit spreads in the token grant. Each row has a stable id, legs (OCC + book side + close side), flattenClass (combo / multileg / option / equity), and flattenable. Sample and manual books are listed but flattenable=false. Read scope is enough.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
kind
query
No
credit_spread | covered_call | wheel | csp | all
Filter by structure kind. Default all.
flattenable
query
No
0 | 1
1 = only rows this token can flatten on Tradier (linked Live/Paper).
Close an open multi-leg as one all-or-none Tradier ticket. Pass positionId from GET /api/v1/positions, or legs[] (OCC symbol + optional quantity/side). type is market (default) or limit (plus price; debit/credit on combos and spreads). dryRun defaults true — preview only, nothing is sent to the book. To place: trade-scoped token, dryRun=false, confirm=true. Preview=true always wins over a place. Covered call with shares + one call uses a combo; credit spreads use multileg; a single leftover option uses an option close.
Auth: Authorization: Bearer clp_… with trade scope
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
positionId
body
No
string
CoveredLoop position id from GET /api/v1/positions. Required unless legs[] is set.
legs
body
No
{ symbol, quantity?, side? }[]
2–4 OCC option legs, or one call plus the underlying. side: short|long|buy_to_close|sell_to_close. If omitted, short options buy-to-close and long options sell-to-close.
accountId
body
No
string
Tradier account. Defaults to the position’s account. Required for custom legs that do not match a listed position.
type
body
No
market | limit | debit | credit | even
Default market. limit requires price and maps to a net debit (typical close) or credit on combo/multileg.
price
body
No
number
Limit / net debit / net credit. Ignored for market.
duration
body
No
day | gtc | pre | post
Default day.
quantity
body
No
integer
Partial close (contracts). Cannot exceed the open size.
dryRun
body
No
boolean
Default true. Must be false to place. Alias: preview=true forces a dry-run even if dryRun=false.
confirm
body
No
boolean
Must be true together with dryRun=false to place a live close. Confirm alone is not enough.
400 missing positionId/legs, confirm required, or Tradier rejected the ticket; 403 read-only token; 402 membership required; 404 position not in grant; 409 halt or structure cannot flatten as one ticket; 429.
curl
curl -sS -X POST https://coveredloop.com/api/v1/positions/flatten \
-H "Authorization: Bearer clp_…" \
-H "Content-Type: application/json" \
-d '{"positionId":"tradier-cs-6YA12345-…","type":"limit","price":0.45}'
# Place (only after a dry-run you accept):
curl -sS -X POST https://coveredloop.com/api/v1/positions/flatten \
-H "Authorization: Bearer clp_…" \
-H "Content-Type: application/json" \
-d '{"positionId":"tradier-cs-6YA12345-…","type":"market","dryRun":false,"confirm":true}'
JavaScript
const headers = {
Authorization: `Bearer ${process.env.COVEREDLOOP_TOKEN}`,
"Content-Type": "application/json",
};
const preview = await fetch("https://coveredloop.com/api/v1/positions/flatten", {
method: "POST",
headers,
body: JSON.stringify({ positionId, type: "limit", price: 0.45 }),
});
const body = await preview.json();
if (!body.dryRun) throw new Error("expected preview");
// Only then, with an explicit confirm from your rules:
const live = await fetch("https://coveredloop.com/api/v1/positions/flatten", {
method: "POST",
headers,
body: JSON.stringify({ positionId, type: "market", dryRun: false, confirm: true }),
});
Open (non-terminal) Tradier orders on granted Live/Paper accounts. Pass account and orderId to read one order, including a filled or canceled ticket. Read scope is enough. Empty list if Tradier is not linked.
Auth: Authorization: Bearer clp_…
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
account
query
No
string
Further limit this request to one granted account id. Alias: accountId. 404 if the id is not in your book; 403 if the token is not allowed to read it.
orderId
query
No
string
With account, return that one order instead of the working list.
One ticket for every open or single-structure close the app can send to Tradier. class=equity buys or sells stock (buy, sell, sell_short, buy_to_cover). class=option opens or closes one contract (sell_to_open covers stock or sells a cash-secured put; buy_to_close / sell_to_close closes a leg). class=combo is a buy-write or a covered close (stock + call together; intent=open or close). class=roll closes one option and opens the replacement. class=spread is a 2–4 leg credit or debit (open with sell_to_open + buy_to_open, close with buy_to_close + sell_to_close). type defaults to market. duration defaults to day. Dry-run is the default and returns Tradier’s preview (cost, commission, buying power). Place only with trade scope, dryRun=false, and confirm=true.
Auth: Authorization: Bearer clp_… with trade scope
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
class
body
Yes
equity | option | combo | roll | spread
Which Live ticket to send.
accountId
body
Yes
string
Tradier account on this token’s grant.
symbol
body
No
string
Equity only. Underlying ticker.
underlying
body
No
string
Option, combo, roll, and spread. Root symbol.
optionSymbol
body
No
OCC
Option and combo. Listed OCC symbol.
quantity
body
No
integer
Equity shares or option contracts.
contracts
body
No
integer
Combo and roll size. Combo stock shares default to contracts × 100 unless shares is set.
Cancel one working Tradier order. Dry-run (the default) asks Tradier whether that order is still working and returns it. It does not cancel. A missing or already finished order is an error, not a success. A live cancel requires trade scope, dryRun=false, and confirm=true. Read the id from GET /api/v1/orders.
Auth: Authorization: Bearer clp_… with trade scope
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
Replace the type, duration, or price on a working Tradier order. Dry-run (the default) asks Tradier whether that order is still working and returns it with the requested change. It does not modify the order. A missing or already finished order is an error. A live change requires trade scope, dryRun=false, and confirm=true. Limit and stop_limit need price. Stop and stop_limit need stop.
Auth: Authorization: Bearer clp_… with trade scope
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer clp_…
Personal access token generated in Settings → API.
Android (Google Play) and iOS (App Store) notify CoveredLoop of subscription events through a normalized webhook. Website Square checkout does not use this route. Native apps or a thin adapter POST after verifying the store receipt.
POST
Record a store subscription event
/api/billing/store-notify
Store / partner
Writes a ledger row and updates membership (purchase, renewal, refund, cancel, freeze, unfreeze, expire, grant). Duplicate storeTxId + kind combinations are ignored.
Auth: Authorization: Bearer $STORE_WEBHOOK_SECRET plus HMAC headers
Name
In
Required
Type
Description
Authorization
header
Yes
Bearer <secret>
STORE_WEBHOOK_SECRET. Must not be CRON_SECRET.
X-CoveredLoop-Timestamp
header
Yes
unix seconds
Request time. Rejected if skew > 5 minutes.
X-CoveredLoop-Signature
header
Yes
sha256=<hex>
HMAC-SHA256 of timestamp + '.' + raw JSON body using STORE_WEBHOOK_SECRET.
Original subscription transaction. Defaults to storeTxId.
planId
body
No
monthly | annual | lifetime
Membership plan.
amountCents
body
No
integer
Gross amount in USD cents. Refunds are stored as negative.
Success
{ "ok": true, "duplicate": false }
Errors
401 unauthorized or missing HMAC; 400 invalid channel/kind/userId/storeTxId or unknown user; 503 if STORE_WEBHOOK_SECRET is unset or equals CRON_SECRET.
Host schedulers (Vercel Cron) call these routes. Production accepts Authorization: Bearer $CRON_SECRET only. Local/dev may use ?secret= for tools. Do not expose these to third-party apps.
GET/POST
Scheduled Tradier sync
/api/cron/live-books
Operations
Quick Tradier sync for every connected book. Nobody has to be logged in, and opening a page does not start it. Vercel Cron calls this every minute. Trading days 8:00 a.m.–4:00 p.m. ET run every call. Other hours run every 15 minutes and the other minutes answer not due. Each run ends as ok, ok-no-changes, skipped-locked, or error: <reason>. ok-no-changes is only after a fresh Tradier pull matched the saved book, and that run still moves as-of. A failed run does not move as-of. A second call while one is still going is skipped-locked. The lock expires after 3 minutes. Never places an order. This route does not replace saved history. If the host plan cannot schedule every minute, point any scheduler at this URL with the same bearer token.
401 unauthorized; 503 if CRON_SECRET is unset in production; 500 with status "error: …" when the pull fails. status "skipped-locked" means another run still holds the lock.
This route no longer replaces a saved book. It answers 404. Only the account owner can replace history, from Settings, and that does not place an order.
During regular hours: incremental quote + technicals rotation. After the close: overnight level-set. Also syncs the listed universe and fires due price alerts.