Generate your PolyTrackers API key
API key generation is available on Pro and Elite. Pro keys are read-only; Elite keys have full read + write access.
PolyTrackers API (External + AI Agent Guide)
This is the production-facing API guide for external developers and AI agents.
- OpenAPI v2:
docs/api/openapi.yaml - Served JSON spec:
/openapi.json(frompublic/openapi.json) - Architecture context:
docs/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/scan/trigger,/api/scan/run - Recommendations & activity:
/api/recommendations,/api/bets/sync - 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) Personal API key bearer
Personal API keys are prefixed ptk_ and are passed as Authorization: Bearer <personal-api-key>. They carry one or more scopes:
signals:read— read anomaly / whale / copy signalsagent:full— full read + write, including real trade execution (Elite only)
Endpoints that accept personal 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 | agent:full |
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)./api/trade/*: 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, but scopes are forced tosignals:readonly (read-only programmatic access). Limit: 1 active personal key per user./api/webhooks(create): up to 5 active webhooks./api/public/whale-signals,/api/public/copy-signals: not allowed (Elite only)./api/trade/*: 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:readand/oragent:full. Limit: 1 active personal key per user./api/trade/execute,/api/trade/history,/api/trade/orders*: allowed (withagent:fullscope for API-key auth)./api/public/whale-signals,/api/public/copy-signals: allowed./api/webhooks(create): up to 50 active webhooks.
Rate limits
| Endpoint | Limit |
|---|---|
POST /api/scan/trigger | Pro: 2/hour, Elite: 10/hour |
POST /api/keys/generate | 5/hour per user |
POST /api/trade/execute | 10/minute per user |
GET /api/public/whale-signals | 120/minute per API key |
GET /api/public/copy-signals | 120/minute per API key |
All rate-limited responses include a Retry-After header (seconds).
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 personal 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 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).
7) Elite-only real trade execution
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"
}'Personal API key with agent:full scope:
curl -X POST "https://polytrackers.com/api/trade/execute" \
-H "Authorization: Bearer $PERSONAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"conditionId":"0x...","side":"YES","amount":20,"idempotencyKey":"..."}'API key lifecycle
Generate personal API key (JWT bearer only)
Pro callers may only request signals:read; Elite callers may additionally request agent:full. Any request is capped at 1 active personal key; revoke the existing key before generating a new one (409 API_KEY_LIMIT_REACHED).
curl -X POST "https://polytrackers.com/api/keys/generate" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"nickname":"Agent Key","expiresInDays":90,"scopes":["signals:read"]}'expiresInDays: 1–365, defaults to 90.scopes: defaults to["signals:read"]. Pro-tier requests foragent:fullare silently downgraded tosignals:read.- 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 personal key for public whale feed (Elite)
curl "https://polytrackers.com/api/public/whale-signals?limit=25" \
-H "Authorization: Bearer $PERSONAL_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 |
|---|---|---|
| Personal 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 }) | type: "open" or type: "all" bulk deletes only the open trades for the wallet. type: "closed" is rejected with 422 CANNOT_DELETE_RESOLVED_TRADE. |
| 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, so the API
returns 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.
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. Only one active personal key per user./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.

