Generate your Agent API Key
Agent API Key generation is available on Pro and Elite. One key works for MCP server access and direct REST/API requests; Pro defaults to read-only access, while Elite can include full agent write access.
PolyTrackers API (External + AI Agent Guide)
This is the production-facing API guide for external developers and AI agents.
Sync guardrail: If REST auth, scopes, tiers, rate limits, trading semantics, or OpenAPI paths change, update the public agent skill at
/skill.mdin the same PR.
- OpenAPI v2:
docs/api/openapi.yaml - Served JSON spec:
/openapi.json(frompublic/openapi.json) - Architecture context:
docs/features/copy-trading/whale-mirroring-spec.md
Scope
This guide/spec covers the full AI agent surface:
- Auth:
/api/auth/signup,/api/auth/login,/api/auth/refresh - Account/Tier:
/api/account,/api/account/stats,/api/account/risk-profile - Discovery:
/api/markets,/api/leaderboard,/api/clob/price,/api/trader-lookup - Anomalies:
/api/anomalies,/api/anomalies/{id},/api/anomalies/performance,/api/scan/trigger,/api/scan/run - Recommendations & activity:
/api/recommendations,/api/bets/sync - Agent API Keys:
/api/keys,/api/keys/generate, plus public feeds - Trading:
/api/trades,/api/trade/execute,/api/trade/history,/api/trade/orders* - Alerts & webhooks:
/api/alerts/preferences,/api/webhooks* - Whale service + ingest webhooks: wallets/roster/whale control +
/api/whale/webhook*
Excluded intentionally:
/api/mock/*simulation helpers/api/cron/*scheduled internal jobs/api/admin/*,/api/stripe/*,/api/telegram/*,/api/onboarding/*and other UI/operator-only routes
Auth modes
1) User auth (session cookie or bearer)
Most user-scoped agent endpoints accept authenticated user context via:
- Supabase session cookie (
sb-*managed cookies) Authorization: Bearer <supabase-jwt-access-token>
2) JWT-only bearer
POST /api/keys/generate strictly verifies Supabase JWT bearer identity.
3) Agent API Key bearer
Agent API Keys are prefixed ptk_ and are passed as Authorization: Bearer <agent-api-key>. The same key works for PolyTrackers MCP server access and direct REST/API requests when it has the required scopes:
signals:read— read-only dataagent:scan— scan trigger where allowedtrade:execute— real trade execution only, after readiness and preflight gates passagent:full— full agent/write/trade access (currently Elite-only for Agent API Keys)
Endpoints that accept Agent API Keys:
| Endpoint | Required scope |
|---|---|
GET /api/anomalies | signals:read |
GET /api/public/whale-signals | signals:read |
GET /api/public/copy-signals | signals:read |
POST /api/trade/execute | trade:execute |
GET /api/trade/history | agent:full |
GET/POST/DELETE /api/trade/orders* | agent:full |
4) Service auth
For whale-service control endpoints:
x-whale-service-secret: <secret>orAuthorization: Bearer <WHALE_SERVICE_SHARED_SECRET>
5) Scan secret
POST /api/scan/run also accepts x-scan-secret: <SCAN_SECRET> (bypasses the tier gate; used by cron/internal automation).
6) Webhook signature auth
POST /api/whale/webhook requires:
x-alchemy-signature = HMAC_SHA256(raw_body, ALCHEMY_WEBHOOK_SIGNING_KEY)
Outbound deliveries from /api/webhooks* are signed with your configured secret as x-polytrackers-signature: sha256=<HMAC_SHA256(raw_body, secret)>.
Tier gating (important)
Effective tier resolution: a user on free with an active trial (trial_ends_at > now) is treated as pro. Tier failures return TIER_UPGRADE_REQUIRED with the required tier and an upgradeUrl.
Free
GET /api/trades: mock trades only, 7-day history window.GET /api/anomalies: max 5 results, 7-day retention window, with a 1-hour visibility delay (detections newer than 1 hour are hidden).POST /api/scan/trigger: not allowed (403).POST /api/keys/generate,GET /api/keys: not allowed (403).POST /api/trade/execute: session callers can execute only when the real-automation beta gate and trading-readiness checks pass. Agent API Key/MCP execution is unavailable because Agent API Keys require Pro+./api/trade/history,/api/trade/orders*: not allowed (403)./api/webhooks(create): not allowed (403)./api/public/whale-signals,/api/public/copy-signals: not allowed (403).
Pro
GET /api/trades: mock trades only, 90-day history window (type=realrejected with403).GET /api/anomalies: max 100 results, 90-day retention window, no delay.POST /api/scan/trigger: allowed, rate limited to 2/hour./api/keys+POST /api/keys/generate: allowed; scopes default tosignals:read, with optionaltrade:executefor real trade execution andagent:scanfor scan automation where allowed. Limit: 2 active Agent API Keys per user for safe rotation./api/webhooks(create): up to 5 active webhooks./api/public/whale-signals,/api/public/copy-signals: not allowed (Elite only).POST /api/trade/execute: session callers can execute only when the real-automation beta gate and trading-readiness checks pass. Agent API Key/MCP execution requirestrade:executescope./api/trade/history,/api/trade/orders*: not allowed.
Elite
- Full
GET /api/tradesaccess (type=realallowed); history window unlimited. GET /api/anomalies: max 200 results, full retention window.POST /api/scan/trigger: allowed, rate limited to 10/hour./api/keys+POST /api/keys/generate: scopes may includesignals:read,trade:execute,agent:scan, and/oragent:full. Limit: 2 active Agent API Keys per user for safe rotation./api/trade/execute,/api/trade/history,/api/trade/orders*: allowed where the route-specific readiness checks pass (trade:executeoragent:fullfor execute API-key auth)./api/public/whale-signals,/api/public/copy-signals: allowed./api/webhooks(create): up to 50 active webhooks.
Rate limits
All Agent API Key requests are rate-limited per key (not per IP or per user), so different cloud IPs / Lambda runtimes sharing a key won't collide. Session requests are limited per user.
| Endpoint | Limit | Scope |
|---|---|---|
POST /api/auth/* | 10/minute | IP |
POST /api/scan/trigger | Pro: 2/hour, Elite: 10/hour | user |
POST /api/keys/generate | 5/hour per user | user |
POST /api/trade/execute | 10/minute per user + 20/minute per API key | user + key |
GET /api/public/whale-signals | 120/minute per API key | API key |
GET /api/public/copy-signals | 120/minute per API key | API key |
429 response shape
All rate-limited responses include a Retry-After header (seconds) and a
structured JSON body so automated clients can back off correctly:
{
"error": "This API key has exceeded its trade execution rate limit. …",
"code": "API_KEY_RATE_LIMITED",
"retryAfter": 7,
"docsUrl": "https://polytrackers.com/docs/api"
}Idempotency for /api/trade/execute
Trade execution is idempotent when you supply an Idempotency-Key header. For
Agent API Key requests the header is required (400 IDEMPOTENCY_KEY_REQUIRED
otherwise); session requests may still pass idempotencyKey in the body.
-
Accepted formats: UUIDv4 (preferred) or any 8–256 printable-ASCII token.
-
Retrying the same key within 24 hours replays the original trade result (
200withidempotencyReused: true) instead of re-executing. -
Two concurrent requests with the same key return
409 TRADE_IN_FLIGHTfor the loser:json{ "error": "trade_in_flight", "code": "TRADE_IN_FLIGHT", "idempotencyKey": "agent-trade-2026-04-20-001", "retryAfter": 5 }
Bot challenge (403)
Session traffic that BotID flags as automated receives:
{
"error": "bot_challenge_failed",
"reason": "automated_traffic_detected",
"suggestedAction": "authenticate_with_api_key",
"docsUrl": "https://polytrackers.com/docs/api"
}Valid Authorization: Bearer ptk_… requests bypass BotID entirely — see
llms.txt.
Quickstart (agent flow)
1) Sign up or log in
curl -X POST "https://polytrackers.com/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"email":"agent@example.com","password":"strong-password"}'Response includes:
access_tokenrefresh_tokentoken_typeexpires_in
2) Read account + tier
curl "https://polytrackers.com/api/account" \
-H "Authorization: Bearer $ACCESS_TOKEN"Returns tier (effective tier, honoring active trial), trialEndsAt, apiKeysCount, walletsCount, onboarding + wallet-link status.
3) Discover markets
curl "https://polytrackers.com/api/markets?query=btc&status=open&sort=volume&limit=25"4) Trigger anomaly scan (Pro/Elite)
curl -X POST "https://polytrackers.com/api/scan/trigger" \
-H "Authorization: Bearer $ACCESS_TOKEN"5) Read anomalies
Session or Agent API Key (signals:read):
curl "https://polytrackers.com/api/anomalies?limit=50&severity=high" \
-H "Authorization: Bearer $ACCESS_TOKEN"Free-tier callers see at most 5 rows, within the last 7 days, and only those detected more than 1 hour ago.
6) Read anomaly detector performance
Aggregate win-rate, average return, and P&L for historical anomaly detections. Backed by the anomaly_performance_daily view.
curl "https://polytrackers.com/api/anomalies/performance?since=2026-01-01T00:00:00Z&until=2026-04-01T00:00:00Z&group_by=month&anomaly_type=SHARP_MOVE" \
-H "Authorization: Bearer $ACCESS_TOKEN"Query parameters:
since,until— ISO-8601 datetimes. Defaults to the last 30 days; the window is capped at 365 days.group_by— one ofday(default),month,anomaly_type,severity,all.anomaly_type,severity— optional filters passed straight through to the view.
Response body:
window—{ since, until }echoing the resolved window (ISO-8601).totals— aggregate{ flagged, resolved, wins, losses, voids, winRate, avgReturnPct, totalPnlUsd, equalDollarPnlPer100 }across the window.series— same shape astotalsbut keyed bycohort(the group_by bucket), sorted ascending.coverage—resolved / flaggedfor the window (0–1).coverageThreshold— the minimum coverage at which headline numbers are considered reliable (currently0.5).headlineReliable—coverage >= coverageThreshold.
equalDollarPnlPer100 is a simulation: $100 flat-staked on every decided anomaly in the cohort, expressed as total dollars of P&L.
Accepts session auth (cookie/JWT) or an Agent API Key with signals:read scope. Responses are cached privately with s-maxage=60, stale-while-revalidate=300.
7) Read unified trade history
curl "https://polytrackers.com/api/trades?type=all&status=all&sort=newest&limit=25&offset=0" \
-H "Authorization: Bearer $ACCESS_TOKEN"Response body includes tier and historyDepthDays (7 for free, 90 for pro, null for elite).
8) Readiness-gated real trade execution
Session auth requires the real-automation beta gate plus trading readiness: Polymarket trading credentials, trading wallet/signing setup, wallet risk config, circuit-breaker state, idempotency, reservations, and audit logging.
Session auth:
curl -X POST "https://polytrackers.com/api/trade/execute" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"conditionId":"0xconditionid",
"side":"YES",
"amount":20,
"limitPrice":0.5,
"idempotencyKey":"agent-trade-2026-04-16-001"
}'Agent API Key with trade:execute scope:
curl -X POST "https://polytrackers.com/api/trade/execute" \
-H "Authorization: Bearer $AGENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"conditionId":"0x...","side":"YES","amount":20,"idempotencyKey":"..."}'Agent API Key lifecycle
Generate Agent API Key (JWT bearer only)
Pro callers may request signals:read, the narrow trade:execute scope, and the narrow agent:scan scope; Elite callers may additionally request agent:full. Accounts can keep 2 active Agent API Keys so you can rotate by generating a new key, updating clients and agents, then revoking the old key (409 API_KEY_LIMIT_REACHED when the cap is reached).
curl -X POST "https://polytrackers.com/api/keys/generate" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"nickname":"Agent API Key","expiresInDays":90,"scopes":["signals:read"]}'expiresInDays: 1–365, defaults to 90.scopes: defaults to["signals:read"]. Addtrade:executeonly when intentionally creating a real-trading key. Pro-tier requests foragent:fullare stripped, whiletrade:executeandagent:scanare allowed where their automation surfaces are enabled.- The raw
api_keyis returned once in the response — store it securely.
List keys
curl "https://polytrackers.com/api/keys" \
-H "Authorization: Bearer $ACCESS_TOKEN"Use Agent API Key for public whale feed (Elite)
curl "https://polytrackers.com/api/public/whale-signals?limit=25" \
-H "Authorization: Bearer $AGENT_API_KEY"Outbound webhooks (Pro/Elite)
Create, list, delete, and test delivery endpoints live under /api/webhooks*:
GET /api/webhooks— list your registrations.POST /api/webhooks— register a new URL with optional filters (minScore,severity[],anomalyTypes[],marketCategories[]) and a secret. Capped at 5 (Pro) / 50 (Elite); over-limit returnsWEBHOOK_LIMIT_REACHED.DELETE /api/webhooks/{id}— soft-delete a registration. The row is retained for audit (withdeleted_atstamped andstatus=paused), it will stop receiving future deliveries, and historicaldelivery_logentries remain queryable.GET /api/webhooks/{id}/deliveries— recent delivery logs.POST /api/webhooks/{id}/test— fire a test payload.
Delivered payloads are signed with the registration's secret; verify
x-polytrackers-signature against sha256=HMAC_SHA256(raw_body, secret).
Deletion & audit retention
PolyTrackers favors soft deletion for user-owned resources so that reporting, billing, copy-trading analytics, and security audits remain reliable. The behavior per-resource is:
| Resource | Endpoint(s) | Behavior |
|---|---|---|
| Agent API Keys | DELETE /api/keys?id=… | Soft-revoke: is_active=false, revoked_at=now(). Authentication is rejected immediately; row is retained for audit. |
| Mock wallets | DELETE /api/wallets, DELETE /api/mock/wallet/{id} | Soft-delete: is_active=false, deleted_at=now(). Whale assignments are detached (active=false, removed_at=now()). mock_trades, whale_activity, and whale_decision_traces are preserved. Wallet names can be reused. |
| Mock trades (single) | DELETE /api/mock/delete-trade?tradeId=… | Only open trades may be deleted. Attempts to delete resolved/closed trades return 422 CANNOT_DELETE_RESOLVED_TRADE. |
| Mock trades (bulk) | DELETE /api/mock/delete-trade (body { type }) | Only type: "open" is accepted for bulk deletes, and only open trades are removed. Any other type is rejected with 400. |
| Outbound webhook registrations | DELETE /api/webhooks/{id} | Soft-delete: deleted_at=now(), status=paused. No future deliveries fire; historical delivery_log remains queryable via GET /api/webhooks/{id}/deliveries. |
| Alert preferences | DELETE /api/alerts/preferences | Hard reset of the preferences row. |
| Roster (whale) assignments | DELETE /api/roster/{walletId} | Detach: row retained, active=false, removed_at=now(). |
| Trade orders | DELETE /api/trade/orders/{id} | Cancels the live order at the CLOB; hard-removes the queued row. |
Closed/resolved mock trades are never user-deletable by design — they feed the
leaderboard, copy-trading scoring, and tier-history analytics. Single-trade
delete attempts on resolved trades return 422 CANNOT_DELETE_RESOLVED_TRADE,
and the database RPCs (delete_mock_trade_atomic,
bulk_delete_mock_trades_atomic) raise cannot_delete_resolved_trade
(SQLSTATE P0101) as a defense in depth.
Whale service + inbound webhooks
Existing whale-service endpoints remain supported and documented in OpenAPI:
- Wallet/roster management (
/api/wallets,/api/roster*) - Service status/config/control (
/api/whale/*) - Webhook ingest/events/replay (
/api/whale/webhook*)
For replay automation, use dryRun: true first, then replay live once validated.
MCP server
PolyTrackers exposes a stateless MCP endpoint for agent clients:
GET /api/mcp— unauthenticated health/capability probe.POST /api/mcp— JSON-RPC 2.0 over Streamable HTTP. SendAuthorization: Bearer <agent-api-key>— use the sameptk_...key as your REST/API examples.GET /api/mcp/events— optional SSE notifications foranomalies,whale_signals,copy_signals, andscan_progress, with: keepaliveevery 15s.
Clients that only support stdio should use @polytrackers/mcp-stdio; see docs/features/mcp/client-setup.md.
Scopes:
signals:read— read-only tool/resource catalog for Pro+.trade:execute— permitspt_trade_executefor Pro+ afterpt_trade_preflightapproval.agent:scan— permitspt_scan_triggerfor Pro+ without granting broader writes.agent:full— current Elite write/execution superset.
Reliability notes
- Handle
429on all rate-limited endpoints and respectRetry-After. - Treat trade execution as idempotent when you provide
idempotencyKey(idempotent replays return200withidempotencyReused: true). POST /api/keys/generatereturns the raw key once — store it securely. Keep at most two active Agent API Keys; rotate by generating a new key, updating clients/agents, then revoking the old key./api/anomalies/{id}may return404when a record falls outside your tier window.TIER_UPGRADE_REQUIREDresponses includerequiredTier,currentTier, andupgradeUrl— surface these to the user/agent verbatim.

