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 summary bubbles, the Reports generator, watch lists, alerts, Profit & Loss, Metrics, portfolio, holdings, and trades. First-party product screens also run as authenticated TanStack Start server functions inside the web app.
Version 2026.08.30.2 · Updated August 30, 2026 · Base URL https://coveredloop.com
v2026.08.30.2 · August 30, 2026. Same list is in the branded PDF.
Account-scoped personal access tokens (clp_…), read-only
Dashboard summary bubbles — full grant and per account
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
Portfolio, holdings, and trades scoped to the token grant
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_…. The token acts as that member (read-only). 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/*, and /metrics honor that pin. Watch lists and price alerts are member-level.
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
GET /api/health?detail=1 (required; not CRON_SECRET)
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
Returns a stable, secret-free payload for uptime tools. HTTP 200 when the database answers; 503 when it does not.
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.
Machine-to-machine access for a member's own data. Create a token in Settings → API. 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 and are read-only. 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.
GET
Current member
/api/v1/me
Member session
Returns the account that owns the access token, a compact membership snapshot, and which brokerage accounts this token may read.
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 / trading costs / open positions / net transfers, the chart-range P&L row (realized, unrealized, current unrealized, 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. 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). 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.
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 within the token grant.
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 within the token grant.
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 within the token grant.
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.
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
Deep health watch
/api/cron/health-watch
Operations
Evaluates database and integration config. Emails ops on degraded/down. Optional daily all-clear.
During regular hours: incremental quote + technicals rotation. After the close: overnight level-set. Also syncs the listed universe and fires due price alerts.