ONTHETAPE Partner API · v1 · read-only

Partner read API

Same firms, verified payouts, and RiseUSD cash-on-hand as the public site — keyed access, cursor pagination, decimal money strings.

Read-only. No writes, no scrape, no second index. Every response is built from the same path as onthetape.io.

Quickstart

1. Get a key

2. Call with Bearer or X-Api-Key

# Health (no key)
curl -sS https://onthetape.io/v1/health | jq .

# Firms (24h ranking)
curl -sS -H "Authorization: Bearer $ONTATAPE_API_KEY" \
  'https://onthetape.io/v1/firms?window=24h&limit=20' | jq .

# Recent verified payouts
curl -sS -H "X-Api-Key: $ONTATAPE_API_KEY" \
  'https://onthetape.io/v1/payouts?limit=30' | jq .

# Cash on hand (all mapped RiseUSD treasuries)
curl -sS -H "Authorization: Bearer $ONTATAPE_API_KEY" \
  'https://onthetape.io/v1/cash-on-hand?limit=50' | jq .

# One firm treasury
curl -sS -H "Authorization: Bearer $ONTATAPE_API_KEY" \
  'https://onthetape.io/v1/firms/tradeify-futures/cash-on-hand' | jq .

Auth

Send the raw API key (not the SHA-256 digest) on every keyed request.

Public vs keyed

Missing / invalid key → 401 unauthorized. Missing scope → 403 forbidden.

Rate limits

Default: 120 requests / 60 seconds per API key (API_V1_RATE_LIMIT). Exceeding the quota returns 429 rate_limited with Retry-After: 60.

Money

All money fields are objects — never JSON numbers:

{
  "amount": "1234.56",
  "currency": "USD"
}

Parse amount as a decimal string. Currency is always USD for v1.

Pagination

Cursor style on list endpoints. Query: limit (default 50, max 200) and cursor.

{
  "pagination": {
    "next_cursor": "c32",
    "has_more": true,
    "limit": 50,
    "count": 50
  }
}

When has_more is true, pass next_cursor as cursor on the next request. Opaque — do not invent cursors.

as_of / freshness

Every successful envelope includes meta.generated_at, meta.as_of, meta.request_id, and meta.api_version.

Endpoints

Full schema: /v1/openapi.json. Windows: 24h 7d 30d 365d ytd alltime.

MethodPathScopeNotes
GET/v1/health—Public liveness
GET/v1/openapi.json—OpenAPI 3.1
GET/v1/metaread:metaCapabilities
GET/v1/firmsread:firmswindow q limit cursor
GET/v1/firms/{id}read:firmsDetail + cash + pulse summary
GET/v1/firms/{id}/payoutsread:payoutsFirm tape
GET/v1/firms/{id}/cash-on-handread:cashLatest RiseUSD
GET/v1/payoutsread:payoutsfirm_id min_amount
GET/v1/cash-on-handread:cashAll mapped treasuries
GET/v1/treasuries · /v1/inflows · /v1/cashread:cashRadar aliases
GET/v1/statsread:firmsWindow rankings
GET/v1/whalesread:payoutsPseudonymous tags
GET/v1/topstep · /v1/lucidread:boardsPublished boards
GET/v1/search?q=read:firmsFirms + recent payouts
GET/v1/sourcesread:metaLane health
GET/v1/stream*SSE URL + poll fallback

Error catalog

Errors are JSON with HTTP status and a stable error.code:

{
  "error": {
    "code": "unauthorized",
    "message": "…",
    "request_id": "req_…",
    "details": {}
  }
}
HTTPcodeWhen
400bad_requestInvalid firm_id, short search q, etc.
401unauthorizedMissing / invalid / unconfigured API key
403forbiddenKey lacks required scope
404not_foundUnknown path, firm, payout, or treasury
429rate_limitedOver key quota; Retry-After: 60
500internalUnexpected server error

OpenAPI

Machine-readable OpenAPI 3.1 document (public, no key):

curl -sS https://onthetape.io/v1/openapi.json | jq '.info, (.paths | keys)'

Full sync patterns and money/as_of rules also live in the repo at docs/integration.md.

MCP server

Stdio MCP server at site/mcp_server.py. Tools wrap the same /v1 handlers (HTTP when a base URL is set; in-process for unit tests).

Environment

VariableRequiredNotes
ONTATAPE_API_KEYpreferredPartner key (raw secret). Falls back to API_V1_DEV_KEY.
API_V1_DEV_KEYlocal altSame key the site process uses in non-production.
ONTATAPE_API_BASErecommendedLive site base, e.g. https://onthetape.io or http://127.0.0.1:8080. Without it, tools call handle_v1 in-process (empty index unless the site module is already loaded).

Run

export ONTATAPE_API_KEY=your_key
export ONTATAPE_API_BASE=https://onthetape.io
python3 site/mcp_server.py

Docker Compose: docker compose --profile mcp run --rm mcp (sets base to the compose api service).

Tools

ToolMaps to
get_capabilitiesGET /v1/meta
list_firmsGET /v1/firms
get_firmGET /v1/firms/{firm_id}
list_payoutsGET /v1/payouts
get_cash_on_handGET /v1/firms/{firm_id}/cash-on-hand
list_cash_on_handGET /v1/cash-on-hand
searchGET /v1/search?q=
get_boardGET /v1/topstep or /v1/lucid
get_healthGET /v1/health (public)

Cursor (mcp.json)

{
  "mcpServers": {
    "onthetape": {
      "command": "python3",
      "args": ["/absolute/path/to/site/mcp_server.py"],
      "env": {
        "ONTATAPE_API_KEY": "your_key",
        "ONTATAPE_API_BASE": "https://onthetape.io"
      }
    }
  }
}

Never commit the key. Prefer a secret store / local env override.