API
View as Markdown

Accounts

Trading accounts with balance status, manual balance events, payouts, and daily snapshots.

GET /accounts

Scope: read:accounts

List your trading accounts.

ParamTypeDescription
include_archivedboolDefault false. Include archived accounts.
broker_keystringFilter by broker (e.g. tradovate, ninjatrader).
account_typeenumlive, demo, paper, funded, live_funded, trading_combine.

GET /accounts/{id}

Scope: read:accounts (also read:balance to include the balance block)

Single account plus its balance status and computed metrics (current balance, high-water mark, drawdown, P&L since start, profit target, max daily loss, max drawdown, deadlines, source preset).

GET /api/v1/accounts/192

Pass ?include=basic to skip the balance block.

GET /accounts/{id}/balance

Scope: read:balance

Same balance block embedded in GET /accounts/{id} — exposed at this dedicated path for clients that want just the balance row plus computed metrics (current balance, high-water mark, drawdown) and the prop-firm rule snapshot (profit target, daily/total drawdown caps, payout split, deadlines). Returns 404 if the account has no balance profile configured.

GET /api/v1/accounts/192/balance

GET /accounts/{id}/balance/events

Scope: read:balance

Paginated audit log of balance state changes: status changes, rule violations, manual updates, payouts, resets, target adjustments.

ParamTypeDescription
limitint1-200, default 50.
offsetint0-based, default 0.
event_typeenumFilter to a single event type (status_change, rule_violation, payout, etc.).

GET /accounts/{id}/balance/payouts

Scope: read:balance

Paginated payout history: amount, status (pending / approved / paid / rejected), profit split, balance before/after, total profit at request time.


POST /accounts

Scope: write:accounts

Create the account shell. Starting balance, prop-firm rules, and trade-template are configured separately via the balance endpoints (or via the settings UI).

FieldTypeRequiredNotes
account_namestring (1–100)yesUnique among your active accounts.
account_typeenumnolive (default), demo, paper, funded, live_funded, trading_combine.
currencyISO 4217noDefaults to USD. Three letters; lowercase is auto-uppercased server-side, so "usd" and "USD" are equivalent.
broker_keystring ≤ 64noFrom the /brokers catalog. Unknown keys return 400.
breakeven_offset_lowdecimal ≤ 0noDefaults to 0.
breakeven_offset_highdecimal ≥ 0noDefaults to 0.

Subscription gate: bill_lim_canAddAccount. Over-cap returns 429 limit_reached.

curl -X POST https://app.tradavity.com/api/v1/accounts \
  -H "Authorization: Bearer tvty_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "account_name": "TopStep XFA #2",
    "account_type": "trading_combine",
    "currency": "USD",
    "broker_key": "topstepx"
  }'

PATCH /accounts/{id}

Scope: write:accounts

Update account_name, account_type, currency, broker_key, breakeven_offset_low, breakeven_offset_high, trade_template_id. Send broker_key: null to unlink the broker; trade_template_id: null to clear the template.

Also accepts is_archived: bool on its own (cannot be combined with other field updates). Setting is_archived: true archives the account; false unarchives. Same disconnect cascade as DELETE /accounts/{id} applies. Returns the updated account.

DELETE /accounts/{id}

Scope: write:accounts

Archive an account. Disconnects auto-sync, clears tokens, and pauses sync as a side effect — same flow the settings UI runs. Returns 204 No Content. Re-DELETE on an already-archived account returns 404 not_found. Use PATCH /accounts/{id} with { "is_archived": false } to unarchive.

Cannot archive your only active account — returns 409 conflict. Trades on the archived account still resolve via API (they keep their account_id and show account.is_archived: true).

curl -X DELETE "https://app.tradavity.com/api/v1/accounts/192" \
  -H "Authorization: Bearer tvty_YOUR_KEY_HERE"

POST /accounts/{id}/balance/events

Scope: write:balance

Record a manual balance event. The API only allows event_type=manual_update — system-generated event types (status changes, rule violations, payouts) are managed by the platform itself.

FieldTypeRequiredNotes
notestring (1–1000)yesWhat this event records.
balance_at_eventdecimalnoSnapshot of current balance.
pnl_at_eventdecimalnoSnapshot of cumulative pnl.
rule_typestring ≤ 50noe.g. profit_target, max_drawdown.
rule_limit / rule_actualdecimalnoFor rule-related notes.
curl -X POST "https://app.tradavity.com/api/v1/accounts/192/balance/events" \
  -H "Authorization: Bearer tvty_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{"note": "Manual reconciliation: broker statement matches journal."}'

If the account has no balance profile set up (no starting balance ever recorded), this returns 400 validation_error with a message telling the caller to initialize the balance first via the settings UI.

POST /accounts/{id}/balance/payouts

Scope: write:balance

Request a payout. Creates a row with status=pending; gross / firm-cut / net amounts are computed from the account’s profit_split_pct. The lifecycle (approve, mark paid, reject) is handled in the settings UI — not yet exposed via the API.

FieldTypeRequiredNotes
gross_amountdecimal > 0yesThe requested amount before firm cut.
notestring ≤ 500no
Payouts are gated by available balance

The server computes effective_balance = current_balance - sum(gross of pending/approved/processing payouts) and rejects requests that exceed it with 400 validation_error — you cannot stack pending payouts that sum past the balance. The check runs inside a row-locked transaction so two concurrent requests can’t both pass.

Always send Idempotency-Key on payout requests. Without it, a network retry can create a second pending payout that would re-debit the balance when both are paid.

curl -X POST "https://app.tradavity.com/api/v1/accounts/192/balance/payouts" \
  -H "Authorization: Bearer tvty_YOUR_KEY_HERE" \
  -H "Idempotency-Key: payout-2026-05-10-monthly" \
  -H "Content-Type: application/json" \
  -d '{"gross_amount": 2500, "note": "May payout"}'