@0xinsider/mcp 2.0.1 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +27 -7
  2. package/dist/catalog.generated.d.ts +4 -0
  3. package/dist/catalog.generated.d.ts.map +1 -1
  4. package/dist/catalog.generated.js +5 -0
  5. package/dist/catalog.generated.js.map +1 -1
  6. package/dist/cli-lib.d.ts +1 -0
  7. package/dist/cli-lib.d.ts.map +1 -1
  8. package/dist/cli-lib.js +48 -8
  9. package/dist/cli-lib.js.map +1 -1
  10. package/dist/client.d.ts +36 -2
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js +42 -4
  13. package/dist/client.js.map +1 -1
  14. package/dist/constants.d.ts +1 -1
  15. package/dist/constants.js +1 -1
  16. package/dist/product-cli/client.d.ts +3 -2
  17. package/dist/product-cli/client.d.ts.map +1 -1
  18. package/dist/product-cli/client.js.map +1 -1
  19. package/dist/sdk/client.d.ts +705 -131
  20. package/dist/sdk/client.d.ts.map +1 -1
  21. package/dist/sdk/client.js +719 -125
  22. package/dist/sdk/client.js.map +1 -1
  23. package/dist/sdk/errors.d.ts +42 -4
  24. package/dist/sdk/errors.d.ts.map +1 -1
  25. package/dist/sdk/errors.js +103 -2
  26. package/dist/sdk/errors.js.map +1 -1
  27. package/dist/sdk/index.d.ts +9 -8
  28. package/dist/sdk/index.d.ts.map +1 -1
  29. package/dist/sdk/index.js +6 -4
  30. package/dist/sdk/index.js.map +1 -1
  31. package/dist/sdk/pagination.d.ts +133 -15
  32. package/dist/sdk/pagination.d.ts.map +1 -1
  33. package/dist/sdk/pagination.js +132 -34
  34. package/dist/sdk/pagination.js.map +1 -1
  35. package/dist/sdk/retry.d.ts +68 -0
  36. package/dist/sdk/retry.d.ts.map +1 -0
  37. package/dist/sdk/retry.js +125 -0
  38. package/dist/sdk/retry.js.map +1 -0
  39. package/dist/sdk/schema.d.ts +1536 -430
  40. package/dist/sdk/schema.d.ts.map +1 -1
  41. package/dist/sdk/stream.d.ts +318 -8
  42. package/dist/sdk/stream.d.ts.map +1 -1
  43. package/dist/sdk/stream.js +503 -56
  44. package/dist/sdk/stream.js.map +1 -1
  45. package/dist/sdk/webhooks.d.ts +18 -3
  46. package/dist/sdk/webhooks.d.ts.map +1 -1
  47. package/dist/sdk/webhooks.js +13 -1
  48. package/dist/sdk/webhooks.js.map +1 -1
  49. package/dist/server.d.ts.map +1 -1
  50. package/dist/server.js +2 -1
  51. package/dist/server.js.map +1 -1
  52. package/dist/tools/explore-markets.d.ts.map +1 -1
  53. package/dist/tools/explore-markets.js +2 -5
  54. package/dist/tools/explore-markets.js.map +1 -1
  55. package/dist/tools/get-insider-radar.d.ts.map +1 -1
  56. package/dist/tools/get-insider-radar.js +3 -10
  57. package/dist/tools/get-insider-radar.js.map +1 -1
  58. package/dist/tools/get-large-positions.d.ts.map +1 -1
  59. package/dist/tools/get-large-positions.js +3 -10
  60. package/dist/tools/get-large-positions.js.map +1 -1
  61. package/dist/tools/get-leaderboard.d.ts.map +1 -1
  62. package/dist/tools/get-leaderboard.js +3 -10
  63. package/dist/tools/get-leaderboard.js.map +1 -1
  64. package/dist/tools/get-market-intel.d.ts.map +1 -1
  65. package/dist/tools/get-market-intel.js +3 -6
  66. package/dist/tools/get-market-intel.js.map +1 -1
  67. package/dist/tools/get-position-timeline.d.ts.map +1 -1
  68. package/dist/tools/get-position-timeline.js +3 -10
  69. package/dist/tools/get-position-timeline.js.map +1 -1
  70. package/dist/tools/get-positions.d.ts +2 -0
  71. package/dist/tools/get-positions.d.ts.map +1 -1
  72. package/dist/tools/get-positions.js +8 -11
  73. package/dist/tools/get-positions.js.map +1 -1
  74. package/dist/tools/get-trader-pnl.d.ts.map +1 -1
  75. package/dist/tools/get-trader-pnl.js +3 -6
  76. package/dist/tools/get-trader-pnl.js.map +1 -1
  77. package/dist/tools/get-trader.d.ts.map +1 -1
  78. package/dist/tools/get-trader.js +3 -6
  79. package/dist/tools/get-trader.js.map +1 -1
  80. package/dist/tools/get-trending-wallets.d.ts.map +1 -1
  81. package/dist/tools/get-trending-wallets.js +3 -10
  82. package/dist/tools/get-trending-wallets.js.map +1 -1
  83. package/dist/tools/get-whale-trades.d.ts.map +1 -1
  84. package/dist/tools/get-whale-trades.js +4 -11
  85. package/dist/tools/get-whale-trades.js.map +1 -1
  86. package/dist/tools/pick-of-the-day.d.ts.map +1 -1
  87. package/dist/tools/pick-of-the-day.js +5 -21
  88. package/dist/tools/pick-of-the-day.js.map +1 -1
  89. package/dist/tools/read-parity.d.ts +1 -0
  90. package/dist/tools/read-parity.d.ts.map +1 -1
  91. package/dist/tools/read-parity.js +69 -44
  92. package/dist/tools/read-parity.js.map +1 -1
  93. package/dist/tools/result.d.ts +31 -0
  94. package/dist/tools/result.d.ts.map +1 -0
  95. package/dist/tools/result.js +70 -0
  96. package/dist/tools/result.js.map +1 -0
  97. package/dist/tools/search-markets.d.ts.map +1 -1
  98. package/dist/tools/search-markets.js +16 -11
  99. package/dist/tools/search-markets.js.map +1 -1
  100. package/package.json +4 -4
@@ -4,6 +4,13 @@ export type AccountIdentity = {
4
4
  user_id: number;
5
5
  credential_id: number;
6
6
  credential_kind: "api_key" | "oauth_grant";
7
+ /** The credential is currently valid; revoked, expired or unknown credentials are rejected. */
8
+ credential_status: "active";
9
+ entitlement: {
10
+ paid_data_access: "active" | "lapsed";
11
+ /** When paid data access is lapsed, the caller should renew the subscription; otherwise null. */
12
+ recovery_action: "renew_subscription" | null;
13
+ };
7
14
  /** Approved OAuth scopes; null for full developer-key access. */
8
15
  scopes: string[] | null;
9
16
  };
@@ -52,7 +59,7 @@ export type ApiDiscovery = {
52
59
  openapi_url: string;
53
60
  /** Unauthenticated API health endpoint. */
54
61
  health_url: string;
55
- authentication: "Bearer API key required for data endpoints; discovery (/api/v1), health, /api/v1/platforms, and the MCP handshake (initialize, ping, tools/list on /api/v1/mcp) are public. A 401 carries WWW-Authenticate with the resource_metadata URL.";
62
+ authentication: "Bearer API key required for data endpoints; discovery (/api/v1), health, /api/v1/platforms, the Pick of the Day commitment ledger (/api/v1/pick-of-the-day/ledger), and the MCP handshake (initialize, ping, tools/list on /api/v1/mcp) are public. A 401 carries WWW-Authenticate with the resource_metadata URL.";
56
63
  /** RFC 9728 protected-resource metadata for the API origin: the document every V1 401 names in its WWW-Authenticate challenge (resource, bearer_methods_supported, resource_documentation). The remote MCP server has its own document at /.well-known/oauth-protected-resource/api/v1/mcp. */
57
64
  protected_resource_metadata_url: string;
58
65
  /** The complete authenticated route index: one entry per authenticated route this spec documents, in "<METHOD> <path>" form, not a representative subset. GET /api/v1 is the unauthenticated entrypoint an agent hits first, so it hands back the whole authenticated surface rather than a sample the caller would have to guess around. The example on GET /api/v1 is abridged for readability -- the live response returns all of them. Kept in lockstep with this spec by review: it is a hand-maintained const in backend/src/api_v1/discovery.rs and no automated check compares the two, so treat this spec as authoritative if they ever disagree. */
@@ -61,26 +68,28 @@ export type ApiDiscovery = {
61
68
  export type ApiError = {
62
69
  object: "error";
63
70
  error: {
64
- code: "bad_request" | "invalid_api_key" | "subscription_required" | "forbidden" | "not_found" | "account_locked" | "rate_limited" | "rate_limit_unavailable" | "internal_error";
71
+ /** FROZEN: an existing value never changes meaning. request_timeout (408, #16146) was added the way insufficient_scope was: the handler did not answer inside the server's 30-second timeout. Retry-After and retry_at ride on it only for a safe method (GET, HEAD); a timed-out mutation may have completed, so check its state and reuse its Idempotency-Key. */
72
+ code: "bad_request" | "invalid_api_key" | "subscription_required" | "forbidden" | "insufficient_scope" | "not_found" | "account_locked" | "rate_limited" | "rate_limit_unavailable" | "internal_error" | "request_timeout";
65
73
  message: string;
66
- doc_url?: string | null;
67
- param?: string | null;
74
+ doc_url?: string;
75
+ param?: string;
68
76
  /** The recommended next request instant (RFC3339), always in the future. Present on every retryable error: `pick_not_released`, `rate_limited`, `rate_limit_unavailable`, and `read_model_warming`. Omitted otherwise. The absolute twin of `Retry-After`; prefer the header for the sleep duration. For `pick_not_released`, the earliest of the next scheduled release, the next automatic selector attempt, the operating-window start, or about 60 seconds. See that response. */
69
- retry_at?: string | null;
70
- /** ADDITIVE (#7209). The specific, actionable cause behind `code`, when there is one more specific than the code itself. `code` keeps its published values, so existing clients are unaffected; new clients branch on `reason`. Omitted when the code already says everything we know. pick_not_released: no Pick of the Day is published for the current product day; schedule one request against retry_at instead of polling. unknown_endpoint: the PATH is not a route on this API -- read GET /api/v1, do not retry. trader_not_tracked: the wallet is real and the URL is right, but the trader is outside the HOT/WARM sync tiers -- stop asking for this wallet. cursor_expired: pagination went stale mid-walk -- re-request the first page and continue. read_model_warming: the requested endpoint cannot serve its read model yet; exact causes are endpoint-specific and can include a cold or contended refresh or a dependency that prevented refresh. database_unavailable: the API's database or its connection pool is temporarily unreachable (a connection-class failure, not a query fault); code stays rate_limit_unavailable, nothing is rate-limited, retry after Retry-After / retry_at. idempotency_in_progress: retain the exact Idempotency-Key and request body, then retry shortly. webhook_delivery_in_progress: retry the URL or signing-secret configuration change after the destination's active request completes. request_accounting_unavailable: accounting capacity is unavailable before the handler executes; retry after Retry-After / retry_at. sandbox_api_key: the credential is a sandbox key (oxi_sk_test_) from POST /api/v1/agents/register, which only the sandbox server accepts -- call the sandbox base URL with it, or get a live key or OAuth access token; do not retry it here. api_key_in_query: the key was sent as a ?token= query parameter, which no route reads because URLs land in logs and history; the key itself was not checked -- resend it as Authorization: Bearer. subscription_inactive: the key is valid but the account's Pro subscription has lapsed (402 subscription_required); permanent until a person reactivates at https://0xinsider.com/billing, which the message names -- stop retrying on a schedule and surface the link. The key owner is emailed once per lapse. */
71
- reason?: "cursor_expired" | "unknown_endpoint" | "pick_not_released" | "trader_not_tracked" | "read_model_warming" | "database_unavailable" | "request_accounting_unavailable" | "idempotency_in_progress" | "webhook_delivery_in_progress" | "sandbox_api_key" | "api_key_in_query" | "subscription_inactive";
77
+ retry_at?: string;
78
+ /** ADDITIVE (#7209). The specific, actionable cause behind `code`, when there is one more specific than the code itself. `code` keeps its published values, so existing clients are unaffected; new clients branch on `reason`. Omitted when the code already says everything we know. pick_not_released: no Pick of the Day is published for the current product day; schedule one request against retry_at instead of polling. unknown_endpoint: the PATH is not a route on this API -- read GET /api/v1, do not retry. trader_not_tracked: the wallet is real and the URL is right, but the trader is outside the HOT/WARM sync tiers -- stop asking for this wallet. cursor_expired: pagination went stale mid-walk -- re-request the first page and continue. read_model_warming: the requested endpoint cannot serve its read model yet; exact causes are endpoint-specific and can include a cold or contended refresh or a dependency that prevented refresh. database_unavailable: the API's database or its connection pool is temporarily unreachable (a connection-class failure, not a query fault); code stays rate_limit_unavailable, nothing is rate-limited, retry after Retry-After / retry_at. idempotency_in_progress: retain the exact Idempotency-Key and request body, then retry shortly. webhook_delivery_in_progress: retry the URL or signing-secret configuration change after the destination's active request completes. request_accounting_unavailable: accounting capacity is unavailable before the handler executes; retry after Retry-After / retry_at. sandbox_api_key: the credential is a sandbox key (oxi_sk_test_) from POST /api/v1/agents/register, which only the sandbox server accepts -- call the sandbox base URL with it, or get a live key or OAuth access token; do not retry it here. api_key_in_query: the key was sent as a ?token= query parameter, which no route reads because URLs land in logs and history; the key itself was not checked -- resend it as Authorization: Bearer. subscription_inactive: the key is valid but the account's Pro subscription has lapsed (402 subscription_required); permanent until a person reactivates at https://0xinsider.com/billing, which the message names -- stop retrying on a schedule and surface the link. The key owner is emailed once per lapse. monthly_quota_exceeded: the account has used the requests Pro includes for the UTC calendar month (429 rate_limited); retry_at and Retry-After name the first of next month, the only retry that can succeed, and the message names https://0xinsider.com/developers, where pay as you go for requests over the quota is turned on. The X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining and X-Monthly-Quota-Reset headers on every authenticated response say how close the account is. invalid_query, invalid_path, invalid_body (400 bad_request, #16146): a query parameter, a path segment or the JSON body did not parse or does not fit the route's schema, so no handler ran; param names the field when the parser named one (a query key, a path segment, a JSON path such as traders[0], or body); fix the request, never retry it as sent. unsupported_media_type (415 bad_request, param content-type): send the body with Content-Type: application/json. payload_too_large (413 bad_request, param body): the body is over 1048576 bytes. method_not_allowed (405 bad_request): the path is a route but not with this method; the Allow header names the methods it serves. ip_rate_limited (429 rate_limited, #16380): the per-address budget every caller behind one IP shares, counted before authentication, is spent; not the key's own window, and the RateLimit-* headers describe that bucket. ip_throttled (429 rate_limited): the address is in a cooldown after sustained over-limit traffic; Retry-After is minutes to days, and a request before it does not shorten the cooldown. */
79
+ reason?: "cursor_expired" | "unknown_endpoint" | "pick_not_released" | "trader_not_tracked" | "read_model_warming" | "database_unavailable" | "request_accounting_unavailable" | "idempotency_in_progress" | "webhook_delivery_in_progress" | "webhook_secret_rotation_not_prepared" | "webhook_secret_rotation_overlap_active" | "sandbox_api_key" | "api_key_in_query" | "subscription_inactive" | "monthly_quota_exceeded" | "invalid_query" | "unknown_query_parameter" | "invalid_path" | "invalid_body" | "unsupported_media_type" | "payload_too_large" | "method_not_allowed" | "ip_rate_limited" | "ip_throttled";
72
80
  };
73
81
  meta: ResponseMeta;
74
82
  };
75
83
  export type ApiErrorBody = {
76
- code: "bad_request" | "invalid_api_key" | "subscription_required" | "forbidden" | "not_found" | "account_locked" | "rate_limited" | "rate_limit_unavailable" | "internal_error";
84
+ /** FROZEN: an existing value never changes meaning. request_timeout (408, #16146) was added the way insufficient_scope was: the handler did not answer inside the server's 30-second timeout. Retry-After and retry_at ride on it only for a safe method (GET, HEAD); a timed-out mutation may have completed, so check its state and reuse its Idempotency-Key. */
85
+ code: "bad_request" | "invalid_api_key" | "subscription_required" | "forbidden" | "insufficient_scope" | "not_found" | "account_locked" | "rate_limited" | "rate_limit_unavailable" | "internal_error" | "request_timeout";
77
86
  message: string;
78
- doc_url?: string | null;
79
- param?: string | null;
80
- /** The recommended next retry instant (RFC3339). Present on every retryable error (reason=pick_not_released, code=rate_limited, code=rate_limit_unavailable, reason=read_model_warming) and omitted otherwise. Always in the future. For pick_not_released: before the 11:00 UTC operating-window start, before a selected pick's stored release, or after a skipped day, it names the automatic system's next boundary. While no candidate exists in the live window it normally names the persisted next automatic selector attempt. Every value is advisory under supported operator actions: manual publication, release-time override, or admin generation can make a pick available first. When the automatic schedule is absent/due or a pick is overdue it degrades to ~60s. Schedule one request and do not poll. Prefer Retry-After for the duration because it is immune to client clock skew. */
81
- retry_at?: string | null;
82
- /** ADDITIVE (#7209). The specific, actionable cause behind `code`, when there is one more specific than the code itself. `code` keeps its published values, so existing clients are unaffected; new clients branch on `reason`. Omitted when the code already says everything we know. pick_not_released: no Pick of the Day is published for the current product day; schedule one request against retry_at instead of polling. unknown_endpoint: the PATH is not a route on this API -- read GET /api/v1, do not retry. trader_not_tracked: the wallet is real and the URL is right, but the trader is outside the HOT/WARM sync tiers -- stop asking for this wallet. cursor_expired: pagination went stale mid-walk -- re-request the first page and continue. read_model_warming: the requested endpoint cannot serve its read model yet; exact causes are endpoint-specific and can include a cold or contended refresh or a dependency that prevented refresh. database_unavailable: the API's database or its connection pool is temporarily unreachable (a connection-class failure, not a query fault); code stays rate_limit_unavailable, nothing is rate-limited, retry after Retry-After / retry_at. idempotency_in_progress: retain the exact Idempotency-Key and request body, then retry shortly. webhook_delivery_in_progress: retry the URL or signing-secret configuration change after the destination's active request completes. request_accounting_unavailable: accounting capacity is unavailable before the handler executes; retry after Retry-After / retry_at. sandbox_api_key: the credential is a sandbox key (oxi_sk_test_) from POST /api/v1/agents/register, which only the sandbox server accepts -- call the sandbox base URL with it, or get a live key or OAuth access token; do not retry it here. api_key_in_query: the key was sent as a ?token= query parameter, which no route reads because URLs land in logs and history; the key itself was not checked -- resend it as Authorization: Bearer. subscription_inactive: the key is valid but the account's Pro subscription has lapsed (402 subscription_required); permanent until a person reactivates at https://0xinsider.com/billing, which the message names -- stop retrying on a schedule and surface the link. The key owner is emailed once per lapse. */
83
- reason?: "cursor_expired" | "unknown_endpoint" | "pick_not_released" | "trader_not_tracked" | "read_model_warming" | "database_unavailable" | "request_accounting_unavailable" | "idempotency_in_progress" | "webhook_delivery_in_progress" | "sandbox_api_key" | "api_key_in_query" | "subscription_inactive";
87
+ doc_url?: string;
88
+ param?: string;
89
+ /** The recommended next retry instant (RFC3339). Present on every retryable error (reason=pick_not_released, code=rate_limited including reason=monthly_quota_exceeded, code=rate_limit_unavailable, reason=read_model_warming) and omitted otherwise. Always in the future. For pick_not_released: before the 11:00 UTC operating-window start, before a selected pick's stored release, or after a skipped day, it names the automatic system's next boundary. While no candidate exists in the live window it normally names the persisted next automatic selector attempt. Every value is advisory under supported operator actions: manual publication, release-time override, or admin generation can make a pick available first. When the automatic schedule is absent/due or a pick is overdue it degrades to ~60s. Schedule one request and do not poll. Prefer Retry-After for the duration because it is immune to client clock skew. */
90
+ retry_at?: string;
91
+ /** ADDITIVE (#7209). The specific, actionable cause behind `code`, when there is one more specific than the code itself. `code` keeps its published values, so existing clients are unaffected; new clients branch on `reason`. Omitted when the code already says everything we know. pick_not_released: no Pick of the Day is published for the current product day; schedule one request against retry_at instead of polling. unknown_endpoint: the PATH is not a route on this API -- read GET /api/v1, do not retry. trader_not_tracked: the wallet is real and the URL is right, but the trader is outside the HOT/WARM sync tiers -- stop asking for this wallet. cursor_expired: pagination went stale mid-walk -- re-request the first page and continue. read_model_warming: the requested endpoint cannot serve its read model yet; exact causes are endpoint-specific and can include a cold or contended refresh or a dependency that prevented refresh. database_unavailable: the API's database or its connection pool is temporarily unreachable (a connection-class failure, not a query fault); code stays rate_limit_unavailable, nothing is rate-limited, retry after Retry-After / retry_at. idempotency_in_progress: retain the exact Idempotency-Key and request body, then retry shortly. webhook_delivery_in_progress: retry the URL or signing-secret configuration change after the destination's active request completes. request_accounting_unavailable: accounting capacity is unavailable before the handler executes; retry after Retry-After / retry_at. sandbox_api_key: the credential is a sandbox key (oxi_sk_test_) from POST /api/v1/agents/register, which only the sandbox server accepts -- call the sandbox base URL with it, or get a live key or OAuth access token; do not retry it here. api_key_in_query: the key was sent as a ?token= query parameter, which no route reads because URLs land in logs and history; the key itself was not checked -- resend it as Authorization: Bearer. subscription_inactive: the key is valid but the account's Pro subscription has lapsed (402 subscription_required); permanent until a person reactivates at https://0xinsider.com/billing, which the message names -- stop retrying on a schedule and surface the link. The key owner is emailed once per lapse. monthly_quota_exceeded: the account has used the requests Pro includes for the UTC calendar month (429 rate_limited); retry_at and Retry-After name the first of next month, the only retry that can succeed, and the message names https://0xinsider.com/developers, where pay as you go for requests over the quota is turned on. The X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining and X-Monthly-Quota-Reset headers on every authenticated response say how close the account is. invalid_query, invalid_path, invalid_body (400 bad_request, #16146): a query parameter, a path segment or the JSON body did not parse or does not fit the route's schema, so no handler ran; param names the field when the parser named one (a query key, a path segment, a JSON path such as traders[0], or body); fix the request, never retry it as sent. unsupported_media_type (415 bad_request, param content-type): send the body with Content-Type: application/json. payload_too_large (413 bad_request, param body): the body is over 1048576 bytes. method_not_allowed (405 bad_request): the path is a route but not with this method; the Allow header names the methods it serves. ip_rate_limited (429 rate_limited, #16380): the per-address budget every caller behind one IP shares, counted before authentication, is spent; not the key's own window, and the RateLimit-* headers describe that bucket. ip_throttled (429 rate_limited): the address is in a cooldown after sustained over-limit traffic; Retry-After is minutes to days, and a request before it does not shorten the cooldown. */
92
+ reason?: "cursor_expired" | "unknown_endpoint" | "pick_not_released" | "trader_not_tracked" | "read_model_warming" | "database_unavailable" | "request_accounting_unavailable" | "idempotency_in_progress" | "webhook_delivery_in_progress" | "webhook_secret_rotation_not_prepared" | "webhook_secret_rotation_overlap_active" | "sandbox_api_key" | "api_key_in_query" | "subscription_inactive" | "monthly_quota_exceeded" | "invalid_query" | "unknown_query_parameter" | "invalid_path" | "invalid_body" | "unsupported_media_type" | "payload_too_large" | "method_not_allowed" | "ip_rate_limited" | "ip_throttled";
84
93
  };
85
94
  export type BatchMarketIntelItem = {
86
95
  /** Zero-based request index. Duplicate inputs keep separate result rows. */
@@ -98,6 +107,7 @@ export type BatchRateLimitMeta = {
98
107
  reset: number;
99
108
  };
100
109
  export type BatchResponseMeta = {
110
+ /** Unique request ID (req_ prefix). The same value as the X-Request-Id response header, the request's usage accounting row and its log lines. */
101
111
  request_id: string;
102
112
  cached: boolean;
103
113
  total_items: number;
@@ -175,17 +185,17 @@ export type ContentSearchResult = {
175
185
  };
176
186
  export type CounterpartyAnalysis = {
177
187
  status: "available" | "partial" | "unavailable";
178
- unavailable_reason?: string | null;
188
+ unavailable_reason?: string;
179
189
  /** Deterministic immutable membership snapshot for this detail response. */
180
- snapshot_id?: string | null;
190
+ snapshot_id?: string;
181
191
  /** Stable digest binding page cursors to one snapshot and execution set. */
182
- analysis_id?: string | null;
192
+ analysis_id?: string;
183
193
  execution_count: number;
184
194
  available_execution_count: number;
185
195
  unavailable_execution_count: number;
186
196
  executions: CounterpartyExecution[];
187
197
  /** Stable cursor after the last execution included in the bounded inline page. */
188
- executions_next_cursor?: string | null;
198
+ executions_next_cursor?: string;
189
199
  };
190
200
  export type CounterpartyExecution = {
191
201
  execution_id: string;
@@ -195,7 +205,7 @@ export type CounterpartyExecution = {
195
205
  taker: CounterpartyParticipant;
196
206
  makers: CounterpartyParticipant[];
197
207
  /** Stable cursor after the last maker included in the bounded inline page. */
198
- makers_next_cursor?: string | null;
208
+ makers_next_cursor?: string;
199
209
  };
200
210
  export type CounterpartyMakerPage = {
201
211
  analysis_id: string;
@@ -203,7 +213,7 @@ export type CounterpartyMakerPage = {
203
213
  execution_id: string;
204
214
  items: CounterpartyParticipant[];
205
215
  /** Cursor bound to the analysis, execution, last full-denominator share total, and wallet. */
206
- next_cursor?: string | null;
216
+ next_cursor?: string;
207
217
  };
208
218
  export type CounterpartyMatchBreakdown = {
209
219
  match_type: "COMPLEMENTARY" | "MINT" | "MERGE";
@@ -216,14 +226,16 @@ export type CounterpartyParticipant = {
216
226
  /** Lowercase Polygon wallet from the exact OrderFilled log. */
217
227
  execution_wallet: string;
218
228
  identity_status: "resolved" | "infrastructure" | "unavailable";
219
- resolved_user_id?: string | null;
220
- wallet_family?: string | null;
221
- resolution_block?: number | null;
222
- resolution_source?: string | null;
223
- display_name?: string | null;
224
- grade?: string | null;
229
+ resolved_user_id?: string;
230
+ wallet_family?: string;
231
+ resolution_block?: number;
232
+ resolution_source?: string;
233
+ display_name?: string;
234
+ grade?: string;
235
+ /** Latest nonfuture recorded wallet-wide trade time for the tracked trader supplying this participant's grade. Omitted when unavailable; not the receipt time or the owner EOA's activity. Trader context is read with the response and is not frozen by execution membership snapshots. */
236
+ last_traded_at?: string;
225
237
  /** 0xinsider profile path segment for this participant, present only when the execution wallet has a tracked trader: `@<username>` when that username resolves to the trader alone, otherwise the trader's lowercase wallet. Percent-encode the part after `@` and append to `https://0xinsider.com/profile/`. */
226
- profile_segment?: string | null;
238
+ profile_segment?: string;
227
239
  maker_fill_count: number;
228
240
  /** Exact decimal shares. */
229
241
  filled_shares: string;
@@ -240,15 +252,29 @@ export type CreateWebhookRequest = {
240
252
  event_types: WebhookEventType[];
241
253
  };
242
254
  export type EventReplayEvent = {
243
- /** Opaque event ID; currently identical to cursor for the whale_alerts.id sequence. */
255
+ /** Opaque event identity: the ef_-encoded whale_alerts.id, stable across cursor formats. Deduplicate on this, never on cursor or sequence. */
244
256
  id: string;
245
257
  type: "whale_trades_inserted";
246
- /** Cursor positioned at this event. */
258
+ /** Cursor positioned at this event: its (inserted_xid, id) commit-order position. Store the page's next_cursor to continue; this one resumes from exactly this event. */
247
259
  cursor: string;
248
- /** Global whale_alerts.id sequence. */
260
+ /** whale_alerts.id of the event. Not monotonic across a replay: events arrive in commit order, so a lower id can follow a higher one when its write finished later. Order and resume by cursor, deduplicate by id. */
249
261
  sequence: number;
250
262
  published_at: string;
251
- payload: Record<string, unknown>;
263
+ /** What the event announces. Every field is present on every event; a field added later is additive, so a client tolerates keys it does not know. */
264
+ payload: {
265
+ /** Whale trades this event announces. One event is minted per stored whale trade, so this is 1. */
266
+ count: number;
267
+ /** The raw whale_alerts.id of the trade, the same number as sequence. GET /api/v1/whale-trades/{id} accepts it and returns the trade with its wallet, grade, size, price and market. */
268
+ whale_alert_id: number;
269
+ /** The Polymarket condition id of the market the trade was in. */
270
+ condition_id: string;
271
+ /** 0xinsider's numeric id for the wallet's trader row. It is not the trd_ id, which is derived from the address; read the address and grade from the whale trade. */
272
+ trader_id: number;
273
+ /** Provider discriminator. Polymarket only. */
274
+ platform: "polymarket";
275
+ };
276
+ /** Present only with expand=trade: the public trade read for this row, the same object GET /api/v1/whale-trades/{id} returns, read at request time from one query per page. traded_at, side, size_usd, price, outcome, token_id, recorded_signal_score and trader.grade_at_trade with its status are the row's event-time facts; trader.grade, trader.username, signal_score, suspicion_score, suspicion_track and market title/slug/category are enrichment that can move after the event. null when that route would answer 404 for the row (its trader or market is not synced yet). */
277
+ trade?: WhaleTrade | null;
252
278
  source: EventReplaySource;
253
279
  freshness: EventReplayFreshness;
254
280
  };
@@ -257,18 +283,36 @@ export type EventReplayFreshness = {
257
283
  observed_at: string;
258
284
  };
259
285
  export type EventReplayMeta = {
260
- /** Unique request ID (req_ prefix). */
286
+ /** Unique request ID (req_ prefix). The same value as the X-Request-Id response header, the request's usage accounting row and its log lines. */
261
287
  request_id: string;
262
288
  cached: boolean;
263
- cache_age_s?: number | null;
289
+ cache_age_s?: number;
264
290
  /** Advisory request weight (relative compute cost). 1 for simple reads; higher for heavier endpoints. Not a credit/price. */
265
291
  cost: number;
266
292
  replay: {
293
+ /** The request cursor in canonical form (an id-only cursor is re-encoded), or the zero position when omitted. */
267
294
  from_cursor: string;
295
+ /** Identical to next_cursor. After a full page, the cursor of the last event; after a page that is not full, the commit horizon itself, since every row below it, matching or not, has been examined. An empty page therefore still advances. */
268
296
  to_cursor: string;
297
+ /** whale_alerts.id component of the request cursor (0 when omitted). */
269
298
  from_sequence: number;
299
+ /** whale_alerts.id of the last event on this page, or from_sequence when the page is empty. Can sit below the position next_cursor encodes after a page that is not full. */
270
300
  to_sequence: number;
271
- ordering: "whale_alerts_id_asc";
301
+ /** Events are ordered by the position at which their write became visible (whale_alerts.inserted_xid), then by whale_alerts.id, and a page is bounded by the oldest write transaction still open when it was read. Before 2026-09-22 this read whale_alerts_id_asc; that order could skip a late-committing lower id (#16180). */
302
+ ordering: "commit_visibility_then_id_asc";
303
+ /** True when committed whale-trade rows newer than this page's commit-visibility horizon exist. They are held until every older write transaction has finished and are served on a later request, so a caught_up page with this true is not the end of the stream: poll again. A long open write transaction on the database (a single-transaction backfill) is what keeps this true for more than a few seconds. */
304
+ pending_beyond_horizon: boolean;
305
+ /** The effective filter set this page ran with and next_cursor is bound to. Absent on an unfiltered walk. */
306
+ filters?: {
307
+ /** The trader parameter as given. */
308
+ trader?: string;
309
+ /** The raw provider condition id after mkt_ is stripped. */
310
+ condition_id?: string;
311
+ min_grade?: "S" | "A" | "B" | "C" | "D" | "F";
312
+ min_size?: number;
313
+ };
314
+ /** The expansions applied to every event on this page; empty when none. */
315
+ expand: "trade"[];
272
316
  };
273
317
  retention: {
274
318
  status: "durable_database";
@@ -276,6 +320,7 @@ export type EventReplayMeta = {
276
320
  cursor_expired: false;
277
321
  };
278
322
  completeness: {
323
+ /** complete: the page carries every durable event matching the filters after the cursor below the commit horizon, up to limit. caught_up: nothing matching after the cursor is visible below the horizon; read pending_beyond_horizon to tell an idle stream from held rows, and note next_cursor has still advanced to the horizon. */
279
324
  status: "complete" | "caught_up";
280
325
  reason: string;
281
326
  };
@@ -300,13 +345,13 @@ export type ExploreGroup = {
300
345
  type: "group";
301
346
  event_slug: string;
302
347
  parent_title: string;
303
- image?: string | null;
304
- platform?: string | null;
305
- category?: string | null;
348
+ image: string | null;
349
+ platform: string | null;
350
+ category: string | null;
306
351
  /** Markets in the event cluster, ranked by volume with condition_id as the tie-breaker. The selected representative is retained within the 12-market cap. */
307
352
  markets: ExploreMarket[];
308
- rep_volume?: number | null;
309
- rep_whales?: number | null;
353
+ rep_volume: number | null;
354
+ rep_whales: number | null;
310
355
  };
311
356
  export type ExploreMarket = {
312
357
  id: string;
@@ -314,57 +359,57 @@ export type ExploreMarket = {
314
359
  /** Non-empty market title. */
315
360
  title: string;
316
361
  /** Provider-native market slug. */
317
- slug?: string | null;
362
+ slug: string | null;
318
363
  /** First-party market page slug used for internal links. */
319
- url_slug?: string | null;
320
- image?: string | null;
321
- icon?: string | null;
322
- category?: string | null;
323
- platform?: string | null;
364
+ url_slug: string | null;
365
+ image: string | null;
366
+ icon: string | null;
367
+ category: string | null;
368
+ platform: string | null;
324
369
  status: "active" | "closed";
325
- volume?: number | null;
326
- liquidity?: number | null;
327
- whale_trade_count?: number | null;
328
- whale_distinct_wallets?: number | null;
329
- whale_total_usd?: number | null;
330
- whale_last_trade_at?: string | null;
331
- end_date?: string | null;
332
- created_at?: string | null;
333
- outcome_yes?: string | null;
370
+ volume: number | null;
371
+ liquidity: number | null;
372
+ whale_trade_count: number | null;
373
+ whale_distinct_wallets: number | null;
374
+ whale_total_usd: number | null;
375
+ whale_last_trade_at: string | null;
376
+ end_date: string | null;
377
+ created_at: string | null;
378
+ outcome_yes: string | null;
334
379
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the YES outcome; null when unavailable (e.g. unsynced markets). */
335
- token_id_yes?: string | null;
336
- outcome_no?: string | null;
380
+ token_id_yes: string | null;
381
+ outcome_no: string | null;
337
382
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the NO outcome; null when unavailable (e.g. unsynced markets). */
338
- token_id_no?: string | null;
339
- event_slug?: string | null;
340
- smart_score?: number | null;
341
- smart_count?: number | null;
342
- smart_label?: string | null;
383
+ token_id_no: string | null;
384
+ event_slug: string | null;
385
+ smart_score: number | null;
386
+ smart_count: number | null;
387
+ smart_label: string | null;
343
388
  /** Display label for the YES/outcome_index=0 side, enriched from provider outcome metadata when available. */
344
- outcome_yes_label?: string | null;
389
+ outcome_yes_label: string | null;
345
390
  /** Display label for the NO/outcome_index=1 side, enriched from provider outcome metadata when available. */
346
- outcome_no_label?: string | null;
391
+ outcome_no_label: string | null;
347
392
  /** Provider-owned YES/outcome_index=0 identifier when available for trade-ticket wiring. */
348
- outcome_yes_provider_id?: number | null;
393
+ outcome_yes_provider_id: number | null;
349
394
  /** Provider-owned NO/outcome_index=1 identifier when available for trade-ticket wiring. */
350
- outcome_no_provider_id?: number | null;
351
- open_interest?: number | null;
352
- oi_change_pct?: number | null;
353
- price_points?: number[][] | null;
354
- no_price_points?: number[][] | null;
355
- last_price?: number | null;
356
- no_last_price?: number | null;
357
- change_pct_24h?: number | null;
358
- no_change_pct_24h?: number | null;
395
+ outcome_no_provider_id: number | null;
396
+ open_interest: number | null;
397
+ oi_change_pct: number | null;
398
+ price_points: number[][] | null;
399
+ no_price_points: number[][] | null;
400
+ last_price: number | null;
401
+ no_last_price: number | null;
402
+ change_pct_24h: number | null;
403
+ no_change_pct_24h: number | null;
359
404
  /** Backend-owned deterministic market discovery score used by the hot sort. */
360
- discover_score?: number | null;
405
+ discover_score: number | null;
361
406
  score_components?: {
362
- volume_signal?: number | null;
363
- whale_signal?: number | null;
364
- liquidity_signal?: number | null;
365
- recency_signal?: number | null;
366
- smart_money_signal?: number | null;
367
- price_move_signal?: number | null;
407
+ volume_signal: number | null;
408
+ whale_signal: number | null;
409
+ liquidity_signal: number | null;
410
+ recency_signal: number | null;
411
+ smart_money_signal: number | null;
412
+ price_move_signal: number | null;
368
413
  missing_price_penalty: number;
369
414
  };
370
415
  freshness?: {
@@ -388,17 +433,18 @@ export type ExportCounts = {
388
433
  estimated_size_mb: number;
389
434
  };
390
435
  export type ExportSourceRange = {
391
- first_pnl_date?: string | null;
392
- last_pnl_date?: string | null;
393
- latest_trade_at?: string | null;
394
- latest_market_activity_at?: string | null;
436
+ first_pnl_date: string | null;
437
+ last_pnl_date: string | null;
438
+ latest_trade_at: string | null;
439
+ latest_market_activity_at: string | null;
395
440
  };
396
441
  export type ExportVolumeReconciliation = {
397
- provider_lifetime_volume?: number | null;
442
+ /** Verified full-history both-sides USD cash volume. Null without coverage; the local activity numerator may cover only a subset of history. */
443
+ provider_lifetime_volume: number | null;
398
444
  exported_activity_volume: number;
399
445
  exported_market_cost_basis: number;
400
- provider_activity_volume_gap?: number | null;
401
- activity_volume_coverage?: number | null;
446
+ provider_activity_volume_gap: number | null;
447
+ activity_volume_coverage: number | null;
402
448
  };
403
449
  /** Current category evidence, independent of the global grade. Pick of the Day stamps only the served display roster; frozen entry snapshots remain unchanged. */
404
450
  export type HolderCategoryEvidence = {
@@ -433,65 +479,92 @@ export type LargePosition = {
433
479
  id: string;
434
480
  /** Provider discriminator. Always polymarket. */
435
481
  platform: "polymarket";
436
- /** Aggregate provider currentValue for this position leg in USD. */
437
- total_size_usd?: number | null;
438
- /** Provider per-position unrealized P&L (trader_markets.unrealized_pnl_num, from Polymarket cashPnl). */
439
- position_unrealized_pnl?: number | null;
482
+ /** Provider currentValue in USD for the outcome named by outcome_label / token_id, and for that outcome only. An absent key means the provider supplied no value for this leg, not a zero position. combined_value_usd carries the wallet's whole-market total. */
483
+ total_size_usd?: number;
484
+ /** Provider unrealized mark-to-market P&L (Polymarket cashPnl) for that same one outcome. An absent key means unavailable, not break-even. */
485
+ position_unrealized_pnl?: number;
486
+ /** The wallet's currentValue across every outcome it holds in this market. Equals total_size_usd unless is_two_sided is true, and is the value the feed ranked this row by. */
487
+ combined_value_usd?: number;
488
+ /** The wallet's unrealized P&L across every outcome it holds in this market. Equals position_unrealized_pnl unless is_two_sided is true. */
489
+ combined_unrealized_pnl?: number;
490
+ /** Whether the wallet holds shares on both outcomes of this market. */
491
+ is_two_sided: boolean;
492
+ /** Every outcome the wallet holds, primary first. holdings[0] restates the top-level per-outcome fields; a further entry is a leg those fields do not describe. No amount here is a share-proportional slice of a both-sides total. */
493
+ holdings: ({
494
+ /** 0 = Yes, 1 = No. */
495
+ outcome_index: number;
496
+ /** The market's label for this outcome. */
497
+ outcome_label?: string;
498
+ /** Polymarket CLOB token id for this outcome; null for an unsynced market. */
499
+ token_id: string | null;
500
+ /** Shares held on this outcome. */
501
+ share_count: number;
502
+ /** Provider average entry price for this outcome. */
503
+ avg_entry_price?: number;
504
+ /** Provider mark price for this outcome. */
505
+ current_price?: number;
506
+ /** Provider currentValue for this outcome. An absent key means unavailable, not zero. */
507
+ value_usd?: number;
508
+ /** Provider unrealized P&L for this outcome. An absent key means unavailable, not break-even. */
509
+ unrealized_pnl?: number;
510
+ })[];
440
511
  /** Live share count for this position. */
441
512
  share_count: number;
442
513
  /** Volume-weighted entry price. */
443
- avg_entry_price?: number | null;
514
+ avg_entry_price?: number;
444
515
  /** Latest provider mark price for the position's token. */
445
- current_price?: number | null;
516
+ current_price?: number;
446
517
  /** Backend-resolved outcome label (provider outcome, else Yes/No from the binary index). */
447
- outcome_label?: string | null;
518
+ outcome_label?: string;
448
519
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets). */
449
- token_id?: string | null;
520
+ token_id: string | null;
450
521
  /** Legs collapsed into this representative row for one (wallet, event, outcome side) group. 1 means standalone. */
451
522
  event_leg_count: number;
452
- /** Aggregate provider currentValue across collapsed sibling legs; equals total_size_usd when event_leg_count = 1. */
453
- event_total_value_usd?: number | null;
523
+ /** Sum of the collapsed sibling legs' own holding values for this (wallet, event) group; equals total_size_usd when event_leg_count = 1, and omitted when any member's value is unknown. */
524
+ event_total_value_usd?: number;
454
525
  first_seen_at: string;
455
526
  last_updated_at: string;
456
527
  trader: {
457
528
  /** Prefixed ID (`trd_...`). */
458
529
  id: string;
459
530
  address: string;
460
- username?: string | null;
531
+ username?: string;
461
532
  grade?: "S" | "A" | "B" | "C" | "D" | "F";
462
- win_rate?: number | null;
533
+ win_rate?: number;
463
534
  /** Trader lifetime realized P&L across all markets. */
464
- pnl?: number | null;
465
- markets_traded?: number | null;
535
+ pnl?: number;
536
+ markets_traded?: number;
466
537
  };
467
538
  market: {
468
539
  /** Prefixed ID (`mkt_...`). */
469
540
  id: string;
470
541
  condition_id: string;
471
- title?: string | null;
472
- slug?: string | null;
473
- event_slug?: string | null;
474
- category?: string | null;
542
+ title?: string;
543
+ slug?: string;
544
+ event_slug?: string;
545
+ category?: string;
475
546
  };
476
547
  };
477
548
  export type LeaderboardEntry = {
478
549
  id: string;
479
550
  address: string;
480
- username?: string | null;
481
- grade?: string | null;
482
- /** Hot-streak tier (trailing-7d cross-sectional percentile); a separate axis from the all-time grade. Null when no recent activity. */
551
+ username?: string;
552
+ grade?: string;
553
+ /** Hot-streak tier (trailing-7d cross-sectional percentile); a separate axis from the all-time grade. Omitted when there is no recent activity. */
483
554
  streak_tier?: "hot" | "rising" | "neutral" | "cooling" | "cold";
484
- score?: number | null;
555
+ score?: number;
485
556
  /** All-time P&L in USD (total_pnl), including unrealized open positions. Kept for back-compat; prefer realized_pnl for the banked figure. */
486
- pnl?: number | null;
557
+ pnl?: number;
487
558
  /** Native realized P&L plus credited maker and taker rebates in USD, with fees already included. The exact numeric value is truncated toward zero to cents before JSON conversion. Wallets without a native snapshot retain their historical stored realized P&L. Omitted when the native snapshot has no net realized value. */
488
- realized_pnl?: number | null;
489
- volume?: number | null;
490
- markets_traded?: number | null;
491
- win_rate?: number | null;
492
- strategy_type?: string | null;
559
+ realized_pnl?: number;
560
+ /** Full-history both-sides USD cash volume from a verified Polymarket user-volume observation. Omitted without coverage. */
561
+ volume?: number;
562
+ markets_traded?: number;
563
+ /** The wallet's win rate across ALL categories, not the filtered one. ?category= decides WHICH wallets are listed (the wallet must be ranked in that category); it does not rescope this field, so a soccer-filtered list still reports each wallet's overall rate. For a per-category record use GET /api/v1/trader/{address}/categories. */
564
+ win_rate?: number;
565
+ strategy_type?: string;
493
566
  platform: string;
494
- last_active?: string | null;
567
+ last_active?: string;
495
568
  };
496
569
  /** Provider-first bucketed OHLC price candles for a market's outcome tokens, derived from the stored token_price_snapshots series (covers open and resolved markets). */
497
570
  export type MarketCandles = {
@@ -502,32 +575,127 @@ export type MarketCandles = {
502
575
  /** One entry per present provider token (YES first, then NO); empty when no tokens have been fetched yet. */
503
576
  outcomes: OutcomeCandles[];
504
577
  };
578
+ export type MarketHolder = {
579
+ /** Composite `pos_<wallet>:<condition_id>:<outcome_index>`, the same id `GET /api/v1/positions` gives this leg. */
580
+ id: string;
581
+ /** `trd_`-prefixed trader id, accepted by `GET /api/v1/trader/{address}`. */
582
+ trader_id: string;
583
+ /** Lowercased proxy wallet. */
584
+ address: string;
585
+ /** Polymarket's public display name from the same holder snapshot; null for a private wallet, which the provider redacts at the source. */
586
+ name: string | null;
587
+ /** The outcome this wallet nets to. A wallet holding both outcomes is listed once, on its net side; see `other_outcome_shares`. */
588
+ side: "YES" | "NO";
589
+ /** Polymarket CLOB token id (ERC1155 asset id, decimal string) for `side`; null when the market has no stored token id. */
590
+ token_id: string | null;
591
+ /** All-time trader grade. This route lists the S/A/B cohort only, the same cohort a Pick of the Day roster lists. */
592
+ grade: "S" | "A" | "B" | null;
593
+ /** Shares held on `side`, from the complete provider scan. */
594
+ shares: number;
595
+ /** Polymarket's own currentValue for this leg, in USD. Null when the snapshot predates the value map. */
596
+ current_value_usd: number | null;
597
+ /** Shares on the other outcome when the wallet holds both. Absent when the wallet is one-sided. */
598
+ other_outcome_shares?: number;
599
+ /** The wallet's last recorded trade anywhere, null when unknown. */
600
+ last_traded_at: string | null;
601
+ /** This wallet's win rate in the market's canonical category (`market.category`): the share of its resolved markets in that category whose realized P&L closed positive, as a 0..1 fraction. Present only with `category_win_rate_status` = `measured`. The same read `GET /api/v1/trader/{address}/categories` serves per wallet. */
602
+ category_win_rate?: number;
603
+ /** The two counts `category_win_rate` is the ratio of, from the same row: `wins / decided` equals the rate. Every resolved Polymarket market the wallet traded in the market's canonical category, at any position size, rebuilt daily. Present only with `category_win_rate_status` = `measured`. */
604
+ category_win_record?: {
605
+ /** Resolved markets in the category that this wallet closed with a profit. */
606
+ wins: number;
607
+ /** Resolved markets in the category that this wallet closed with a profit or a loss. A market resolved at zero realized P&L is in neither count. */
608
+ decided: number;
609
+ };
610
+ /** For an esports market, the game `category_win_rate` and `category_win_record` were measured in: `LoL`, `CS2`, `Dota 2`, `Valorant`, `Call of Duty`, `Honor of Kings`, `Mobile Legends: Bang Bang`, `Overwatch`, `Rainbow Six Siege`, `Rocket League` or `StarCraft II`. Present only when the wallet's record in that game clears the 5-resolved-market floor, in which case the rate and record are the game's rather than the `Esports` bucket's. Absent when the rate is the bucket's (the wallet's game history is under the floor), on every non-esports market, and beside every non-measured status. Label the rate with this when present and with the market's `category` otherwise. */
611
+ category_win_rate_game?: string;
612
+ /** Why `category_win_rate` is present or absent: `measured` (rate present), `not_enough_data` (under the floor of 5 decided markets in the category), or `unavailable` (the market has no canonical category, or the read failed; retry later). Always present on this route. */
613
+ category_win_rate_status: "measured" | "not_enough_data" | "unavailable";
614
+ category_evidence?: HolderCategoryEvidence;
615
+ /** Days since this wallet's first trade. The five badge fields are present together, only for a wallet that draws at least one badge. */
616
+ wallet_age_days?: number | null;
617
+ /** True when the wallet's first trade was under 30 days ago. */
618
+ is_new_wallet?: boolean;
619
+ /** Distinct markets the wallet has traded. */
620
+ markets_traded?: number | null;
621
+ /** True when the wallet is flagged as automated. */
622
+ is_bot?: boolean;
623
+ /** The wallet's X handle without the @, when linked. */
624
+ x_username?: string | null;
625
+ };
626
+ export type MarketHoldersMarket = {
627
+ /** `mkt_`-prefixed market id. */
628
+ id: string;
629
+ condition_id: string;
630
+ title: string | null;
631
+ slug?: string;
632
+ event_slug?: string;
633
+ /** The canonical category bucket `category_win_rate` is measured in. */
634
+ category: string | null;
635
+ outcome_yes: string | null;
636
+ outcome_no: string | null;
637
+ token_id_yes: string | null;
638
+ token_id_no: string | null;
639
+ end_date?: string;
640
+ /** A settled market's roster is whatever the provider still lists as open; it empties as holders redeem. */
641
+ status: "open" | "closed" | "resolved";
642
+ };
643
+ export type MarketHoldersScan = {
644
+ /** `cached`: the shared holder snapshot, at most 180 s old at compute time. `live`: the provider answered a fresh complete walk for this compute. */
645
+ source: "cached" | "live";
646
+ /** Always true on a served roster. An incomplete or unstable scan is a 503, never a partial list. */
647
+ complete: boolean;
648
+ /** When the provider walk that produced the holder population finished. */
649
+ fetched_at: string | null;
650
+ /** Every distinct wallet the complete walk saw with open shares, graded or not. The roster lists the graded S/A/B subset. */
651
+ wallet_count: number;
652
+ };
653
+ export type MarketHoldersSideGrades = {
654
+ s: number;
655
+ a: number;
656
+ b: number;
657
+ };
658
+ /** Roster totals BEFORE any `outcome` or `min_grade` filter, so a page always knows the whole market it was cut from. */
659
+ export type MarketHoldersTotals = {
660
+ /** Distinct graded wallets with net exposure; a two-sided wallet counts once. */
661
+ graded_count: number;
662
+ yes_count: number;
663
+ no_count: number;
664
+ yes_shares: number;
665
+ no_shares: number;
666
+ /** Polymarket currentValue summed over the graded wallets netting YES. */
667
+ yes_usd: number;
668
+ /** Polymarket currentValue summed over the graded wallets netting NO. */
669
+ no_usd: number;
670
+ yes_grades: MarketHoldersSideGrades;
671
+ no_grades: MarketHoldersSideGrades;
672
+ };
505
673
  export type MarketIntel = {
506
674
  market: {
507
675
  id: string;
508
676
  condition_id: string;
509
677
  title: string;
510
- slug?: string | null;
511
- category?: string | null;
512
- platform?: string | null;
678
+ slug: string | null;
679
+ category: string | null;
680
+ platform: string | null;
513
681
  };
514
682
  /** Outcome-aware flow from all tracked whale trades in the window, without a grade filter. BUY YES and SELL NO add net exposure; BUY NO and SELL YES subtract it. Gross buy/sell volumes count both outcomes. Top positions are separately graded. Direction uses unrounded net: negative is NO, otherwise YES; the zero tie-break is not conviction. Canonical; smart_money is a deprecated byte-identical alias. */
515
683
  sharp_money: {
516
684
  net_flow_usd: number;
517
685
  direction: "YES" | "NO";
518
686
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets). */
519
- token_id?: string | null;
687
+ token_id: string | null;
520
688
  whale_trade_count: number;
521
689
  buy_volume_usd: number;
522
690
  sell_volume_usd: number;
523
691
  top_positions: ({
524
692
  id: string;
525
693
  address: string;
526
- username?: string | null;
527
- grade?: string | null;
694
+ username: string | null;
695
+ grade: string | null;
528
696
  side: "YES" | "NO";
529
697
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets). */
530
- token_id?: string | null;
698
+ token_id: string | null;
531
699
  size_usd: number;
532
700
  })[];
533
701
  };
@@ -536,18 +704,18 @@ export type MarketIntel = {
536
704
  net_flow_usd: number;
537
705
  direction: "YES" | "NO";
538
706
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets). */
539
- token_id?: string | null;
707
+ token_id: string | null;
540
708
  whale_trade_count: number;
541
709
  buy_volume_usd: number;
542
710
  sell_volume_usd: number;
543
711
  top_positions: ({
544
712
  id: string;
545
713
  address: string;
546
- username?: string | null;
547
- grade?: string | null;
714
+ username: string | null;
715
+ grade: string | null;
548
716
  side: "YES" | "NO";
549
717
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets). */
550
- token_id?: string | null;
718
+ token_id: string | null;
551
719
  size_usd: number;
552
720
  })[];
553
721
  };
@@ -557,9 +725,9 @@ export type MarketSearchResult = {
557
725
  id: string;
558
726
  condition_id: string;
559
727
  title: string;
560
- slug?: string | null;
561
- category?: string | null;
562
- platform?: string | null;
728
+ slug: string | null;
729
+ category: string | null;
730
+ platform: string | null;
563
731
  status: "active" | "closed";
564
732
  };
565
733
  export type MarketSnapshot = {
@@ -567,45 +735,45 @@ export type MarketSnapshot = {
567
735
  id: string;
568
736
  condition_id: string;
569
737
  provider: string;
570
- title?: string | null;
571
- slug?: string | null;
572
- page_slug?: string | null;
573
- event_slug?: string | null;
574
- category?: string | null;
738
+ title: string | null;
739
+ slug: string | null;
740
+ page_slug: string | null;
741
+ event_slug: string | null;
742
+ category: string | null;
575
743
  status: "active" | "closed";
576
- description?: string | null;
577
- image?: string | null;
744
+ description: string | null;
745
+ image: string | null;
578
746
  /** Polymarket series slug from the canonical identity row, null when unavailable. A sports series identifies a league and must not be used as a per-matchup grouping key. */
579
- series_slug?: string | null;
580
- market_type?: string | null;
581
- market_result?: string | null;
582
- created_at?: string | null;
583
- end_date?: string | null;
584
- resolved_at?: string | null;
747
+ series_slug: string | null;
748
+ market_type: string | null;
749
+ market_result: string | null;
750
+ created_at: string | null;
751
+ end_date: string | null;
752
+ resolved_at: string | null;
585
753
  };
586
754
  outcomes: ({
587
755
  side: "yes" | "no";
588
756
  label: string;
589
- token_id?: string | null;
590
- current_price?: number | null;
757
+ token_id?: string;
758
+ current_price?: number;
591
759
  top_of_book: MarketSnapshotTopOfBook;
592
760
  })[];
593
761
  liquidity: {
594
762
  source: string;
595
- volume_usd?: number | null;
596
- liquidity_usd?: number | null;
597
- volume_24h_usd?: number | null;
763
+ volume_usd: number | null;
764
+ liquidity_usd: number | null;
765
+ volume_24h_usd: number | null;
598
766
  /** Always null. Polymarket snapshot prices come from outcome top-of-book midpoints. */
599
- last_price?: number | null;
767
+ last_price: number | null;
600
768
  };
601
769
  sports: {
602
770
  status: "fresh" | "stale" | "not_live" | "unavailable";
603
771
  source: string;
604
- live_match_key?: string | null;
605
- live_league_key?: string | null;
772
+ live_match_key?: string;
773
+ live_league_key?: string;
606
774
  /** Live-score period and elapsed may be omitted when unavailable (older responses use null). A score entry may omit full_name when it equals team; fall back to team. Distinct aliases and score admission markers are preserved. */
607
- live_score?: Record<string, unknown> | null;
608
- reason?: string | null;
775
+ live_score?: Record<string, unknown>;
776
+ reason?: string;
609
777
  };
610
778
  freshness: {
611
779
  market_data: MarketSnapshotFreshness;
@@ -619,20 +787,20 @@ export type MarketSnapshot = {
619
787
  export type MarketSnapshotFreshness = {
620
788
  status: "fresh" | "stale" | "available" | "not_live" | "unavailable";
621
789
  source: string;
622
- as_of?: string | null;
790
+ as_of?: string;
623
791
  /** Age-relative freshness bound when known. Omitted for live_sports: its as_of records compute start, while its two-second freshness marker starts at publication. */
624
- stale_after_s?: number | null;
625
- reason?: string | null;
792
+ stale_after_s?: number;
793
+ reason?: string;
626
794
  };
627
795
  export type MarketSnapshotTopOfBook = {
628
796
  status: "available" | "unavailable";
629
797
  source: string;
630
- best_bid?: number | null;
631
- best_ask?: number | null;
632
- spread_bps?: number | null;
633
- bid_depth_usdc?: number | null;
634
- ask_depth_usdc?: number | null;
635
- reason?: string | null;
798
+ best_bid?: number;
799
+ best_ask?: number;
800
+ spread_bps?: number;
801
+ bid_depth_usdc?: number;
802
+ ask_depth_usdc?: number;
803
+ reason?: string;
636
804
  };
637
805
  /** Price and spread trust metadata returned only when GET /api/v1/market/{condition_id}/snapshot includes expand=trust. */
638
806
  export type MarketSnapshotTrust = {
@@ -660,14 +828,23 @@ export type OutcomeCandles = {
660
828
  };
661
829
  export type PickHolder = {
662
830
  address: string;
663
- name?: string | null;
831
+ name: string | null;
664
832
  /** All-time trader grade (S, A, B, C, D, F). */
665
- grade?: string | null;
833
+ grade: string | null;
666
834
  /** 0xinsider profile path segment this wallet links to: `@<username>` when that username resolves to this wallet alone, otherwise the lowercase wallet. Percent-encode the part after `@` and append to `https://0xinsider.com/profile/`. Stamped at serve time; absent on a body cached before the field shipped. */
667
- profile_segment?: string | null;
835
+ profile_segment?: string;
668
836
  shares: number;
669
- /** This wallet's win rate in the pick's canonical category bucket (the pick's `category` field, e.g. Basketball -- label the rate with it, never with the narrower `display_category` league): the share of the wallet's resolved markets in that category whose realized P&L closed positive, as a 0..1 fraction. Present only with `category_win_rate_status` = `measured`, on `display_holders` entries, and only when the wallet clears the resolved-market floor; recomputed at serve time from the current category read model, not frozen with the pick. Absent on `holders` entries, legacy rows, and payloads predating the field. */
670
- category_win_rate?: number | null;
837
+ /** This wallet's win rate in the pick's canonical category bucket (the pick's `category` field, e.g. Basketball -- label the rate with it, never with the narrower `display_category` league, except when `category_win_rate_game` is present, in which case the rate is that game's and is labelled with it): the share of the wallet's resolved markets in that category whose realized P&L closed positive, as a 0..1 fraction. Present only with `category_win_rate_status` = `measured`, on `display_holders` entries, and only when the wallet clears the resolved-market floor; recomputed at serve time from the current category read model, not frozen with the pick. Absent on `holders` entries, legacy rows, and payloads predating the field. */
838
+ category_win_rate?: number;
839
+ /** The two counts `category_win_rate` is the ratio of, read from the same row: `wins / decided` equals the rate. Counts every resolved Polymarket market the wallet traded in the pick's canonical category (or in its game, when `category_win_rate_game` is present), at any position size; the counts are rebuilt daily. Present only with `category_win_rate_status` = `measured`; absent otherwise and on payloads predating the field. */
840
+ category_win_record?: {
841
+ /** Resolved markets in the category that this wallet closed with a profit. */
842
+ wins: number;
843
+ /** Resolved markets in the category that this wallet closed with a profit or a loss. A market resolved at zero realized P&L is in neither count. */
844
+ decided: number;
845
+ };
846
+ /** For an esports pick, the game `category_win_rate` and `category_win_record` were measured in, by the same name the pick's `display_category` uses for it: `LoL`, `CS2`, `Dota 2`, `Valorant`, `Call of Duty`, `Honor of Kings`, `Mobile Legends: Bang Bang`, `Overwatch`, `Rainbow Six Siege`, `Rocket League` or `StarCraft II`. Present only when the wallet's record in that game clears the 5-resolved-market floor, in which case the rate and record are the game's rather than the `Esports` bucket's. Absent when the rate is the bucket's (the wallet's game history is under the floor), on every non-esports pick, beside every non-measured status, and on payloads predating the field. Label the rate with this when present and with `category` otherwise. */
847
+ category_win_rate_game?: string;
671
848
  /** Why `category_win_rate` is present or absent on a `display_holders` entry: `measured` (rate present), `not_enough_data` (the wallet is below the resolved-market floor of 5 in the category), or `unavailable` (the annotation read failed; retry later). Absent entirely on `holders` entries, legacy rows, and payloads predating the field -- absence means the roster was never annotated, not a small sample. */
672
849
  category_win_rate_status?: "measured" | "not_enough_data" | "unavailable";
673
850
  /** Days since this wallet's first trade. Stamped at serve time from the wallet's current trader record, never frozen with the pick. The five badge fields are present together, and only for a wallet that carries at least one badge; all absent means no badge, or a body cached before the fields shipped. */
@@ -686,7 +863,7 @@ export type PickOfTheDay = {
686
863
  /** Always 'full' for an authenticated Pro key. */
687
864
  state: "full";
688
865
  /** The pick's local publication date (YYYY-MM-DD). */
689
- pick_date: string;
866
+ pick_date?: string;
690
867
  /** Stable 1-based slot within the product day's ranked picks. */
691
868
  pick_rank?: number;
692
869
  /** The complete ranked picks for this product day, ordered by pick_rank. Thin days contain fewer items; the selector never fabricates rows. */
@@ -696,55 +873,59 @@ export type PickOfTheDay = {
696
873
  /** Same-day picks selected but not yet released, ordered by pick_rank. Additive and optional: present only while at least one unreleased slot exists. Each slot exposes only its rank and schedule -- no market identity before release. Schedule the next read from the earliest release_at instead of polling. */
697
874
  scheduled_picks?: ScheduledPickSlot[];
698
875
  /** Human-readable matchup (e.g. "Portugal vs. Uzbekistan"). */
699
- matchup: string;
876
+ matchup?: string;
700
877
  /** Frozen canonical calibration/report bucket (e.g. "Basketball", "MMA", or "Soccer"). Existing semantics are unchanged; presentation consumers should prefer display_category when present. */
701
- category: string;
878
+ category?: string;
702
879
  /** Frozen public presentation category. For supported Polymarket sports this is the exact verified provider event identity: an official league (e.g. "WNBA" or "UFC"), the esports title (e.g. "CS2", "LoL", "Dota 2" or "Valorant"), or a soccer competition whose official mark we vendor (e.g. "LaLiga", "Premier League", "Serie A" or "UEFA Champions League"). Only identities with a vendored official mark are split out; every other competition keeps its canonical bucket, so "Soccer" remains a live value; otherwise it equals category. An esports pick keeps the pooled "Esports" bucket in category, so a per-title label never implies a per-title measured cohort. Additive and optional for mixed-version client compatibility. */
703
880
  display_category?: string;
704
881
  /** Provider platform (e.g. "polymarket"). */
705
- platform: string;
882
+ platform?: string;
706
883
  /** The pick's stored release instant. Normally the current provider kickoff minus one hour; an operator may override it. The actual publish instant can trail it because of worker or claim delay. */
707
- release_at: string;
884
+ release_at?: string;
708
885
  /** True only before the pick's stored release instant (a pre-release embargo flag); effectively always false on a served, already-published pick. To detect that the backed game has kicked off, use `game_started`. */
709
- is_locked: boolean;
886
+ is_locked?: boolean;
710
887
  /** True once the backed game's kickoff has passed (kickoff <= now). When true the snapshotted pre-game price is no longer actionable. Absent for a legacy pick with no stored kickoff (treat as not-started). */
711
888
  game_started?: boolean;
712
889
  /** Settlement outcome of the backed side; 'pending' until the market resolves. */
713
- outcome: "pending" | "win" | "loss" | "void";
890
+ outcome?: "pending" | "win" | "loss" | "void";
714
891
  /** Pre-formatted SETTLEMENT STATUS for display: "Win" / "Loss" / "Void" / "Pending" -- the outcome enum above as a label. Convenience only; outcome is the source value. NOTE: this is the win/loss STATUS, not the backed side. The backed side is pick_outcome_label ("Belgium (-2.5)") -- a different field answering a different question. */
715
892
  outcome_display?: string;
716
893
  /** The backed side phrased as a bet: a team for a moneyline (e.g. "Portugal"), the handicap line for a spread (e.g. "Belgium (-2.5)"), or "{team} to advance" for a knockout advancement market (e.g. "Spain to advance"). */
717
- pick_outcome_label: string;
718
- /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the backed outcome; null when unavailable (e.g. unsynced markets). */
719
- token_id?: string | null;
894
+ pick_outcome_label?: string;
895
+ /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the backed outcome; omitted when unavailable (e.g. unsynced markets). */
896
+ token_id?: string;
720
897
  /** The backed side phrased as a bet (e.g. "Portugal to win"). */
721
- position: string;
898
+ position?: string;
722
899
  /** One-line summary of which side sharp money is backing. Required on every item in `picks`: a current-day published pick whose required holder proof is not safely readable is listed in `proof_pending_picks` instead of being served with a partial success shape or a synthetic zero, and the route returns 503 read_model_warming only when no published pick has readable proof. */
723
- side_summary: string;
900
+ side_summary?: string;
724
901
  /** Public V1 compatibility count of S/A smart-money wallets on the backed side. The first-party/internal current policy counts S/A/B; historical rows retain their frozen policy's count. Required on every item in `picks`: a current-day published pick whose required holder proof is not safely readable is listed in `proof_pending_picks` instead of being served with a partial success shape or a synthetic zero, and the route returns 503 read_model_warming only when no published pick has readable proof. */
725
- smart_wallet_count: number;
902
+ smart_wallet_count?: number;
726
903
  /** Best public V1-compatible S/A smart-money grade on the backed side. The first-party/internal current policy can select B, but a current B-only grade is omitted by the stable V1 adapter. Historical rows retain their frozen policy's grade. A current-day published pick with pending legacy proof, unknown-future proof, or structurally invalid current-policy proof returns 503 before this success schema is served. Resolved legacy proof remains readable on both current-day and archive/history responses. */
727
- top_grade?: string | null;
904
+ top_grade?: string;
728
905
  /** Deprecated (#7170): no longer populated for picks selected on/after the calibration-edge change; omitted (absent) for new picks (the field uses skip_serializing_if, so a null value is dropped from the JSON rather than serialized as null). Permanently frozen-legacy -- retained for historical picks, with no removal or replacement planned, so no v2 is implied. Historical picks may still carry a value. Legacy meaning: category win-rate edge as a fraction (the backed-side cohort's win rate in this category minus the non-market-maker category baseline, e.g. 0.09 = +9 points), paired with category_edge_sample. */
729
- category_edge_pct?: number | null;
906
+ category_edge_pct?: number;
730
907
  /** Deprecated (#7170): no longer populated for picks selected on/after the calibration-edge change; omitted (absent) for new picks (the field uses skip_serializing_if, so a null value is dropped from the JSON rather than serialized as null). Permanently frozen-legacy -- retained for historical picks, with no removal or replacement planned, so no v2 is implied. Historical picks may still carry a value. Legacy meaning: pooled count of resolved markets behind category_edge_pct (the headline's n). */
731
- category_edge_sample?: number | null;
908
+ category_edge_sample?: number;
732
909
  /** Recency-weighted graded-flow magnitude in USD; omitted when <= 0. */
733
- smart_usd?: number | null;
734
- /** Pre-game snapshot probability (0..1) for the backed side. */
735
- backed_price?: number | null;
910
+ smart_usd?: number;
911
+ /** Frozen pre-game probability (0..1) for the backed side, written once at publication. It is the Polymarket CLOB order book midpoint at release, not an executed fill: a buyer lifts the ask, so a subscriber's own entry is usually a little worse than this price. */
912
+ backed_price?: number;
736
913
  /** Full-only disclosure when backed_price was recovered from provider history within 30 seconds before publication. Render beside the price. Absent for ordinary publication captures and teasers; this is a historical reference, not an executed fill. */
737
914
  entry_price_note?: string;
738
915
  /** Pre-formatted backed_price as cents-on-the-dollar odds, to ONE decimal: "62.0c" / "99.9c". Never rounded to a whole cent -- a 99.9c favorite is not a 100c certainty. Convenience only; backed_price is the source value. Omitted when backed_price is. */
739
- odds_display?: string | null;
740
- /** Gross return on a $100 stake at the snapshotted price (100 / backed_price). */
741
- return_per_100?: number | null;
742
- /** Pre-formatted return_per_100 as USD with cents and thousands separators: "$161.29" / "$1,250.00". The GROSS return (the $100 stake included), so it carries no sign. Convenience only; return_per_100 is the source value. Omitted when return_per_100 is. */
743
- payout_display?: string | null;
744
- /** Pre-formatted PROFIT on the $100 stake -- return_per_100 minus the 100 stake, i.e. the payout net of what you put in -- as a signed USD string: "+$61.29". Distinct from payout_display, which is gross. Omitted when return_per_100 is. */
745
- profit_display?: string | null;
916
+ odds_display?: string;
917
+ /** The flat stake the published record puts on every pick, in USD: 1000 since 2026-09-22 (it was 100 before). Present exactly when return_usd is, so a reader never has to know the stake from anywhere else. */
918
+ stake_usd?: number;
919
+ /** Gross return of stake_usd at the frozen midpoint price (stake_usd / backed_price). A real fill pays the ask, so an executed stake usually returns a little less. Omitted with backed_price. */
920
+ return_usd?: number;
921
+ /** The same return on a literal $100 (100 / backed_price), kept for compatibility: the field predates stake_usd and its name promises the $100 basis, so a client that scales it to its own stake stays right. Present exactly when return_usd is. */
922
+ return_per_100?: number;
923
+ /** Pre-formatted return_usd as USD with cents and thousands separators: "$1,612.90" / "$12,500.00". The GROSS return (the stake included), so it carries no sign. Convenience only; return_usd is the source value. Omitted when return_usd is. */
924
+ payout_display?: string;
925
+ /** Pre-formatted PROFIT on the stake -- return_usd minus stake_usd, i.e. the payout net of what you put in -- as a signed USD string: "+$612.90". Distinct from payout_display, which is gross. Omitted when return_usd is. */
926
+ profit_display?: string;
746
927
  /** Backend-owned CLV capture disposition. "pending" means no capture decision exists yet; terminal provider or quality statuses remain distinguishable. The raw close price and timestamp are never serialized. */
747
- clv_status: string;
928
+ clv_status?: string;
748
929
  /** Backend-owned CLV evidence basis. `frozen_displayed_entry` uses the persisted displayed entry. `historical_provider_entry` uses a known-CLOB point at or before publication. `historical_provider_price_match` requires the latest point in the prior hour to match. `historical_provider_nearby_price_match` requires a matching point within five minutes before publication. Source-null bases preserve unknown original provenance. */
749
930
  clv_basis?: string;
750
931
  /** Closing-line value toward the backed side, computed as (close / entry - 1) * 100. The basis-specific provider p entry must match the stored display; historical_provider_price_match also requires source provenance to remain null and its latest entry to be within the one-hour window at or before publication. Every basis requires a later quality-checked p close from the same series in the bounded post-entry, pre-kickoff window. Omitted when not measured. */
@@ -753,52 +934,52 @@ export type PickOfTheDay = {
753
934
  clv_display?: string;
754
935
  /** Backend-owned CLV formula text with the entry probability, close probability, and rounded result. Provider timestamps remain private. */
755
936
  clv_explanation?: string;
756
- /** Net return for the pick in the existing $100 stake units. Omitted when the outcome is not valued. */
937
+ /** Net return for the pick in stake units (return_usd / stake_usd - 1); one unit is one stake_usd stake, and the figure is the same under any stake size. Omitted when the outcome is not valued. */
757
938
  unit_score?: number;
758
939
  /** Backend-formatted signed unit score, present exactly when unit_score is present. */
759
940
  unit_score_display?: string;
760
941
  /** First-party/internal backed-side sharp-money dollar consensus as a fraction 0..1: the share of current-policy sharp dollars on the backed side. Omitted on current public V1 rows when the B-inclusive value has no reconstructible S/A equivalent. A conviction signal, NOT a probability or expected-value claim. Frozen at generation. */
761
- sharp_pct?: number | null;
942
+ sharp_pct?: number;
762
943
  /** Market-implied probability of the backed side as a fraction 0..1 (equals backed_price), re-exposed alongside sharp_pct for the WHY breakdown. */
763
- market_pct?: number | null;
764
- /** First-party/internal consensus edge = sharp_pct - market_pct, the conviction-vs-price gap (how much more of the current-policy sharp money sits on this side than the price implies). Omitted on current public V1 rows when the B-inclusive value has no reconstructible S/A equivalent. This is NOT an expected-value or guaranteed edge. Null when either input is null. */
765
- consensus_edge_pct?: number | null;
944
+ market_pct?: number;
945
+ /** First-party/internal consensus edge = sharp_pct - market_pct, the conviction-vs-price gap (how much more of the current-policy sharp money sits on this side than the price implies). Omitted on current public V1 rows when the B-inclusive value has no reconstructible S/A equivalent. This is NOT an expected-value or guaranteed edge. Omitted when either input is unavailable. */
946
+ consensus_edge_pct?: number;
766
947
  /** First-party/internal team-directional commitment read at selection time: the fraction (0..1) of the backed side's current-policy graded sharp-money DOLLARS held by wallets read one-way rather than hedged: no opposite leg on this market worth at least 10% of the backed leg (Polymarket's own currentValue pair), and no opposing team across the game's markets where the wallet's synced legs are fresh. Current public V1 rows omit this B-inclusive read because its historical S/A equivalent is not reconstructed. A high value means the graded pile is really committed to this side; a low one means much of it is hedged or unreadable. Omitted when the read was not computed (a pick selected before the field existed, an ungroupable game, an empty graded pile, or a pile where no holder carried usable evidence) -- which is NOT the same as 0.0, a computed reading that classified holders and found none one-way. */
767
- directional_confidence?: number | null;
948
+ directional_confidence?: number;
768
949
  /** Graded backed-side holders read as one-way-committed on this game. */
769
- one_way_holder_count?: number | null;
950
+ one_way_holder_count?: number;
770
951
  /** Graded backed-side holders read as HEDGED across the game's markets. */
771
- hedged_holder_count?: number | null;
952
+ hedged_holder_count?: number;
772
953
  /** The one-way holders' share of the backed-side graded dollars (the confidence's numerator). */
773
- one_way_graded_usd?: number | null;
954
+ one_way_graded_usd?: number;
774
955
  /** Backed-side graded dollars the confidence is measured against (its denominator). */
775
- total_graded_usd?: number | null;
956
+ total_graded_usd?: number;
776
957
  /** The qualifying category expert whose sport-specific record and real position earned this pick its top selection tier. The first-party/internal current policy admits S/A/B; public V1 exposes a compatible S/A expert and omits a current-policy B-grade expert: a candidate backed by one outranks every candidate without one. Present only on the full payload. Omitted when no wallet qualified on the backed side, on picks generated before the field existed, and on the first-party web teaser, which withholds all backed-side evidence. Frozen at SELECTION time — the wallet's position can move before the pick renders. */
777
958
  qualifying_expert?: {
778
959
  /** Wallet address of the qualifying expert. */
779
960
  address: string;
780
961
  /** Provider display name, or null for an unnamed wallet. */
781
- name?: string | null;
962
+ name: string | null;
782
963
  /** 0xinsider grade letter. The first-party/internal current Pick of the Day policy counts S, A, and B; public V1 exposes only the compatible S/A expert. */
783
- grade?: string | null;
964
+ grade: string | null;
784
965
  /** The canonical sport bucket the win rate was measured over (for example Basketball). Can be BROADER than the pick's display_category, which names an exact league such as NBA — label the rate with this field, never with display_category. */
785
966
  canonical_category: string;
786
967
  /** Share of this wallet's resolved markets in canonical_category whose realized P&L came out positive, as a 0..1 fraction. Above 0.60 by construction for a source=v1 expert; null for an expert who qualified on the category-skill v2 definition only. Deliberately NOT phrased as "closed profitable": the metric counts realized P&L above zero, so a resolved winner the wallet never redeemed sits at zero and counts against it. */
787
- win_rate?: number | null;
968
+ win_rate: number | null;
788
969
  /** Resolved markets in canonical_category behind win_rate. At least 10 by construction for a source=v1 expert; null with win_rate. */
789
- n_resolved?: number | null;
970
+ n_resolved: number | null;
790
971
  /** Current expert policy 10 does not require a category-skill v2 specialist in any sport; in every sport a specialist raises the candidate's rank tier rather than gating it. Standard specialists need a positive edge_lower_95 over enough independent events and enough net backing on the backed side; the floors are not published. Fresh healthy records below the shared model's live sample floor can qualify; stale, unknown and degraded records cannot. Historical records preserve which definition qualified the wallet: v1, the profitability rate (win_rate over n_resolved), or v2, the forward-only category-skill calibration edge (edge_lower_95 over independent_event_count). Absent on picks frozen before the v2 definition existed; read absence as v1. A Tennis pick frozen under gate policy v4 or later carries v2 only: a v1 rate stopped qualifying a tennis expert at v4. A Tennis pick frozen under an earlier policy can still carry v1 with a win rate. */
791
972
  source?: "v1" | "v2";
792
973
  /** 95% lower bound of the wallet's mean calibration edge over the market price in canonical_category, in probability units (0.08 is 8 points). Positive by construction for a v2 expert; present on a v1 expert only when the wallet also holds a live v2 row. */
793
- edge_lower_95?: number | null;
974
+ edge_lower_95?: number;
794
975
  /** Point estimate behind edge_lower_95. */
795
- edge_mean?: number | null;
976
+ edge_mean?: number;
796
977
  /** Independent canonical events behind the edge. At least 10 by construction for a v2 expert. */
797
- independent_event_count?: number | null;
978
+ independent_event_count?: number;
798
979
  /** Polymarket's own currentValue for this wallet on the backed outcome, in USD, as of selection. At least 1000 by construction through gate policy v7; the standard floor is 500 from v8. From gate policy v5 the floor is read on the net: position_usd minus opposite_position_usd is at least that floor, and the pick re-verifies that net against the live holder snapshot when it is released. */
799
980
  position_usd: number;
800
981
  /** The same wallet's currentValue on the OTHER outcome of this market, in USD, as of selection. Present from gate policy v5, when the floor moved to net exposure; a wallet long both sides does not qualify. Absent on picks frozen before v5, which never read the leg. 0 is a measured one-way position, not an absence. */
801
- opposite_position_usd?: number | null;
982
+ opposite_position_usd?: number;
802
983
  /** When the skill read model behind the evidence was last rebuilt: trader_category_stats.computed_at for a source=v1 expert, category_skill_v2_current.as_of for a source=v2 expert. */
803
984
  stats_computed_at: string;
804
985
  /** Present from expert policy 6. Current expert policy 10 retains the longshot requirement of live v2 only, with a positive lower bound over a large sample, large net backed value and no meaningful opposite value. Historical policy 6: a specialist required large net backed value, no meaningful opposite value, and either a live v2 positive lower bound over a large sample or a high v1 rate over enough resolved markets. Tennis requires v2. The floors are not published. */
@@ -807,32 +988,32 @@ export type PickOfTheDay = {
807
988
  lane_probability?: number;
808
989
  /** Canonical provider probability pair branch; absent on standard experts. */
809
990
  lane_probability_source?: "p";
810
- } | null;
991
+ };
811
992
  trust?: PickTrust;
812
993
  /** Public V1 S/A compatibility count on the backed side (equals the adapted smart_wallet_count). The first-party/internal current policy counts S/A/B. Historical rows retain their frozen policy's count. */
813
- traders?: number | null;
994
+ traders?: number;
814
995
  /** Raw backed-side sharp-money USD frozen at generation. This is the Sharp USD value, not the recency-weighted smart_usd which decays. Omitted on current public V1 rows when the B-inclusive value has no reconstructible S/A equivalent. */
815
- backed_sharp_usd?: number | null;
996
+ backed_sharp_usd?: number;
816
997
  /** Bounded S/A compatibility projection of the frozen sharp-money holders on the backed side. Current full payloads expose the complete S/A/B roster in display_holders; historical rows can retain their earlier frozen shape. */
817
- holders?: PickHolder[] | null;
998
+ holders?: PickHolder[];
818
999
  /** Full-only complete provider-confirmed S/A/B holder roster for the current Pick of the Day backing policy. Omitted for teaser, no-pick, and historical rows whose frozen holder proof predates this policy. Each entry may additionally carry `category_win_rate` / `category_win_rate_status`: the wallet's win rate in the pick's canonical `category`, stamped at serve time from the current category read model (the same annotation the sports sharp-money chips carry). The bounded `holders` compatibility projection never carries these fields. */
819
- display_holders?: PickHolder[] | null;
1000
+ display_holders?: PickHolder[];
820
1001
  /** Exact S/A smart-money proof count on the backed side. The current display_holders roster can be longer because it also carries B-grade smart-money holders. */
821
- holder_count?: number | null;
1002
+ holder_count?: number;
822
1003
  /** Optional editorial note attached to the pick. */
823
- editorial_note?: string | null;
1004
+ editorial_note?: string;
824
1005
  /** Required truthful thesis. With at least one profitable-wallet holder: Profitable wallets hold {pick_outcome_label}[, led by a grade-{top_grade} trader]. Without holder backing: 0xInsider's Pick of the Day is {pick_outcome_label}. Wallet counts are not appended. */
825
- thesis: string;
1006
+ thesis?: string;
826
1007
  /** Canonical web market URL. */
827
- market_url?: string | null;
828
- /** The canonical /event game-page slug (one neutral page per game), null when the game has no neutral event page. */
829
- event_slug?: string | null;
830
- /** Backend-resolved /event destination slug for this pick's source market; null is an authoritative no-link decision. */
831
- event_link_slug?: string | null;
1008
+ market_url?: string;
1009
+ /** The canonical /event game-page slug (one neutral page per game); omitted when the game has no neutral event page. */
1010
+ event_slug?: string;
1011
+ /** Backend-resolved /event destination slug for this pick's source market; its absence is an authoritative no-link decision. */
1012
+ event_link_slug?: string;
832
1013
  /** Provider-first sports context for the pick's market (team logos, league branding, live score). Full-state only; omitted when the pick is not a team-sports market. */
833
1014
  sports_context?: PickSportsContext;
834
1015
  /** Risk disclaimer shown with every pick. */
835
- disclaimer: string;
1016
+ disclaimer?: string;
836
1017
  /** Published same-day picks whose holder proof is not readable yet, ordered by pick_rank. Additive and optional: present only while at least one such pick exists. While present, `picks` carries only the proof-readable picks and `pick_count` counts them. Schedule the next read from the earliest retry_at instead of polling. The route returns 503 read_model_warming only when no published pick has readable proof. */
837
1018
  proof_pending_picks?: ProofPendingPickSlot[];
838
1019
  /** Frozen admission classification, full payload only. The specialist lane exempts two probability rejects and adds no rank bonus. Historical rows remain standard. */
@@ -881,34 +1062,63 @@ export type PickOfTheDayArchiveEntry = {
881
1062
  /** Provider (Polymarket Gamma) market thumbnail URL (markets.image); omitted (not null) when the market has no image. Public regardless of the backed-side gate, so present for pending rows too. */
882
1063
  image_url?: string;
883
1064
  /** The backed side's outcome label. Omitted for a still-pending pick when the request is not from an authenticated Pro key. */
884
- pick_outcome_label?: string | null;
885
- /** Best public V1-compatible S/A smart-money grade on the backed side; a current B-only grade is omitted by the stable V1 adapter, while historical rows retain their frozen policy's grade. null when no smart-money wallet backs the pick, when a pending legacy proof has not yet upgraded, or when the stored holder policy is unknown-future or structurally invalid. Resolved legacy history remains supported. */
886
- top_grade?: string | null;
1065
+ pick_outcome_label?: string;
1066
+ /** Best public V1-compatible S/A smart-money grade on the backed side; a current B-only grade is omitted by the stable V1 adapter, while historical rows retain their frozen policy's grade. Omitted when no smart-money wallet backs the pick, when a pending legacy proof has not yet upgraded, or when the stored holder policy is unknown-future or structurally invalid. Resolved legacy history remains supported. */
1067
+ top_grade?: string;
887
1068
  /** Settlement outcome of the backed side; 'pending' until the market resolves. */
888
1069
  outcome: "pending" | "win" | "loss" | "void";
889
1070
  /** Pre-formatted settlement status for display: "Win" / "Loss" / "Void" / "Pending" -- the outcome enum above as a label, from the same formatter the pick payload's outcome_display uses. Convenience only; outcome is the source value. */
890
1071
  outcome_display?: string;
891
- /** Gross return on a $100 stake on this resolved pick: a win returns 100 / backed_price, a loss returns 0, a void refunds 100. A loss always returns 0 (the whole stake is lost regardless of price). Omitted (not null) only for a still-pending pick or a resolved WIN with no frozen price (a win's payout needs the price); mirrors the backend skip-when-absent behavior and the route-client optional (non-nullable) schema. */
1072
+ /** The flat stake this row was valued at, in USD: 1000 since 2026-09-22 (100 before). Every row of the record is valued at the current stake, including picks published before the change. Present exactly when return_usd is. */
1073
+ stake_usd?: number;
1074
+ /** Gross return of stake_usd on this resolved pick: a win returns stake_usd / backed_price, a loss returns 0, a void refunds stake_usd. A loss always returns 0 (the whole stake is lost regardless of price). The operand is published beside it as backed_price on exactly the same rows, so the entry never has to be recovered by inverting this number. Omitted (not null) only for a still-pending pick or a resolved WIN with no frozen price (a win's payout needs the price); mirrors the backend skip-when-absent behavior and the route-client optional (non-nullable) schema. */
1075
+ return_usd?: number;
1076
+ /** The same return on a literal $100 (a win returns 100 / backed_price, a loss 0, a void 100), kept for compatibility: the field predates stake_usd and its name promises the $100 basis. Present exactly when return_usd is. */
892
1077
  return_per_100?: number;
893
- /** Pre-formatted return_per_100 as USD with cents: "$200.00". Present exactly when return_per_100 is -- it is formatted from that already-gated value -- so it is omitted for a still-pending pick, an unpriced win, and any pick whose backed side is withheld. Convenience only; return_per_100 is the source value. */
1078
+ /** Pre-formatted return_usd as USD with cents: "$2,000.00". Present exactly when return_usd is -- it is formatted from that already-gated value -- so it is omitted for a still-pending pick, an unpriced win, and any pick whose backed side is withheld. Convenience only; return_usd is the source value. */
894
1079
  payout_display?: string;
1080
+ /** Frozen price of the backed side (0..1) that return_usd and return_per_100 were computed from: on a win, stake_usd / backed_price equals return_usd. It is the Polymarket CLOB order book midpoint at release, frozen write-once at publication, not an executed fill: a buyer lifts the ask, so a subscriber's own entry is usually a little worse than this price. Present exactly when return_usd is, so it is omitted for a still-pending pick, an unpriced win, and any pick whose backed side is withheld. */
1081
+ backed_price?: number;
895
1082
  /** Closing-line value toward the backed side, computed as (close / entry - 1) * 100. Omitted when the row is gated, ineligible, or not measured. */
896
1083
  clv_pct?: number;
897
1084
  /** Backend-formatted signed CLV percentage, present exactly when clv_pct is present. */
898
1085
  clv_display?: string;
1086
+ /** Entry operand of clv_pct: the frozen pick probability the close is compared against. It equals backed_price, which CLV eligibility requires. Present exactly when clv_pct is. */
1087
+ clv_entry_price?: number;
1088
+ /** Close operand of clv_pct: the last valid Polymarket probability before the close bound (kickoff, or the first instant the live feed reported the game in progress when that came earlier). Present exactly when clv_pct is; the close timestamp stays private. */
1089
+ clv_close_price?: number;
899
1090
  /** Whether CLV applies. A visible resolved pick published after kickoff is not_applicable. */
900
1091
  clv_applicability?: "applicable" | "not_applicable";
901
- /** Backend-owned CLV formula text or the reason that CLV does not apply or is unavailable. */
1092
+ /** Backend-owned CLV text. A measured row names the entry, then the close, then the formula (close / entry - 1) x 100 and its rounded result; otherwise it gives the reason CLV does not apply or is unavailable. */
902
1093
  clv_explanation?: string;
903
- /** Exact backend CLV capture disposition for this visible row. Pending and terminal provider or quality statuses are distinguishable; raw close evidence is never serialized. */
904
- clv_status: string;
1094
+ /** Exact backend CLV capture disposition for this visible row. Pending and terminal provider or quality statuses are distinguishable; capture timestamps are never serialized, while a measured row's entry and close prices are published as clv_entry_price and clv_close_price. */
1095
+ clv_status?: string;
905
1096
  /** Backend-owned CLV evidence basis. Source-null price-match bases preserve unknown original provenance. `historical_provider_nearby_price_match` requires a matching Polymarket point within five minutes before publication. */
906
1097
  clv_basis?: string;
907
- /** Net return for this pick in stake units, where one unit is the existing $100 stake. Omitted when the backed side is withheld or the pick is not valued. */
1098
+ /** Net return for this pick in stake units (return_usd / stake_usd - 1), where one unit is one stake_usd stake; the same figure under any stake size. Omitted when the backed side is withheld or the pick is not valued. */
908
1099
  unit_score?: number;
909
1100
  /** Backend-formatted signed unit score, present exactly when unit_score is present. */
910
1101
  unit_score_display?: string;
911
1102
  };
1103
+ /** The frozen identity of the pick, exactly as the hash was taken over it. Served byte for byte as it was hashed -- keys sorted by UTF-8 byte value, no insignificant whitespace -- so a verifier concatenates and hashes with nothing to reconstruct. Property order below is the wire order. The outcome is deliberately NOT part of it: surviving a corrected outcome unchanged is the case the commitment exists for. Worked example: {"backed_price":"0.545000","condition_id":"0xabc","kickoff":"2026-09-20T23:05:00Z","pick_date":"2026-09-20","pick_outcome_index":1,"pick_outcome_label":"Lakers","pick_rank":1,"platform":"polymarket"} with the nonce 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f hashes to 44d18fa5e2aa3a2bf3c971dcc9317c8ccbdfd5480a4773b6d8ffd5fbeeea84dc. */
1104
+ export type PickOfTheDayCommitmentPayload = {
1105
+ /** Frozen pre-game price of the backed side, 0..1, as the plain decimal text of the stored NUMERIC at full stored precision, trailing zeros included. A string, never a number: a float round-trip would change the bytes and break the hash. Deliberately not normalized -- 0.545000 stays "0.545000". */
1106
+ backed_price: string;
1107
+ /** Provider condition id of the backed market. */
1108
+ condition_id: string;
1109
+ /** Frozen provider kickoff, whole seconds, UTC, literal Z. Fixed precision, never a shortest-lossless rendering. */
1110
+ kickoff: string;
1111
+ /** ET product day (YYYY-MM-DD). */
1112
+ pick_date: string;
1113
+ /** Index of the backed outcome within the market. */
1114
+ pick_outcome_index: 0 | 1;
1115
+ /** Frozen display label of the backed outcome. */
1116
+ pick_outcome_label: string;
1117
+ /** 1-based daily slot. */
1118
+ pick_rank: number;
1119
+ /** Provider platform. */
1120
+ platform: string;
1121
+ };
912
1122
  export type PickOfTheDayHitRate = {
913
1123
  /** Number of decided picks that won. */
914
1124
  wins: number;
@@ -922,9 +1132,11 @@ export type PickOfTheDayHitRate = {
922
1132
  void: number;
923
1133
  /** Number of picks still pending resolution (excluded from the hit rate). */
924
1134
  pending: number;
925
- /** Cumulative profit (USD) of a $100/pick strategy over visible valued decided picks: a priced win pays 100/backed_price - 100, every visible loss pays -100 independent of price, and a void pays 0. An unpriced visible win and a current non-Insider row whose price is gated remain in wins/losses but are excluded from price-derived totals. */
1135
+ /** The flat stake every money figure here assumes, in USD: 1000 since 2026-09-22 (100 before). Always present. */
1136
+ stake_usd?: number;
1137
+ /** Cumulative profit (USD) of a stake_usd-per-pick strategy over visible valued decided picks: a priced win pays stake_usd/backed_price - stake_usd, every visible loss pays -stake_usd independent of price, and a void pays 0. An unpriced visible win and a current non-Insider row whose price is gated remain in wins/losses but are excluded from price-derived totals. */
926
1138
  net_profit_usd: number;
927
- /** Total staked (USD) = 100 * count of visible valued decided picks: every visible loss plus every priced win. Void, unpriced wins, and current non-Insider rows whose price is gated are excluded. */
1139
+ /** Total staked (USD) = stake_usd * count of visible valued decided picks: every visible loss plus every priced win. Void, unpriced wins, and current non-Insider rows whose price is gated are excluded. */
928
1140
  staked_usd: number;
929
1141
  /** Return on the staked amount as a percentage (net_profit_usd / staked_usd * 100, to 1 decimal); 0 when nothing is staked. */
930
1142
  roi_pct: number;
@@ -976,60 +1188,163 @@ export type PickOfTheDayHitRate = {
976
1188
  series?: {
977
1189
  /** The decided pick's publish date (YYYY-MM-DD). */
978
1190
  date: string;
979
- /** Running cumulative $100/pick profit (USD) through this pick; valued losses and priced wins are booked, while a non-valued decided row carries profit forward unchanged. */
1191
+ /** Running cumulative stake_usd-per-pick profit (USD) through this pick; valued losses and priced wins are booked, while a non-valued decided row carries profit forward unchanged. */
980
1192
  net_profit_usd: number;
981
1193
  /** Running rolling hit rate (wins / decided * 100, to 1 decimal) through this pick. */
982
1194
  hit_rate_pct: number;
983
1195
  }[];
984
1196
  };
1197
+ /** The commitment ledger: every published pick, ascending, in the state its commitment is actually in. The counts are derived from entries in the same pass that builds it. */
1198
+ export type PickOfTheDayLedger = {
1199
+ /** One entry per published (pick_date, pick_rank), ascending by pick_date then pick_rank. */
1200
+ entries: PickOfTheDayLedgerEntry[];
1201
+ /** Number of entries, all states included. */
1202
+ entry_count: number;
1203
+ /** Entries committed to and not yet settled. */
1204
+ sealed_count: number;
1205
+ /** Entries committed to and verifiable now. */
1206
+ opened_count: number;
1207
+ /** Entries carrying no commitment, so provable by nothing: the honest size of the unprovable part of the record. It only stops growing; no pick is ever retro-sealed. */
1208
+ uncommitted_count: number;
1209
+ };
1210
+ /** One ledger entry. Read `state` to know which shape you have; the three are disjoint. */
1211
+ export type PickOfTheDayLedgerEntry = PickOfTheDayLedgerSealedEntry | PickOfTheDayLedgerOpenedEntry | PickOfTheDayLedgerUncommittedEntry;
1212
+ /** A settled pick whose commitment is open: the nonce plus the exact payload the hash was taken over. Concatenate the payload bytes as received with the decoded nonce and sha256 them to reproduce commitment_hash. */
1213
+ export type PickOfTheDayLedgerOpenedEntry = {
1214
+ state: "opened";
1215
+ /** ET product day the pick belongs to (YYYY-MM-DD). */
1216
+ pick_date: string;
1217
+ /** 1-based daily slot within the product day. */
1218
+ pick_rank: number;
1219
+ /** sha256(canonical_json(payload) || nonce), lowercase hex, no 0x prefix. Publishable the moment the pick releases: without the nonce it is not invertible. */
1220
+ commitment_hash: string;
1221
+ /** The 32-byte nonce the hash was taken over, lowercase hex, no 0x prefix. Secret while the pick is live: a pick payload is low entropy, so a published nonce on a live pick would hand out the backed side. */
1222
+ commitment_nonce: string;
1223
+ /** The construction the hash was taken with, stated in the response so a verifier never has to guess the serialization. */
1224
+ commitment_algo: "sha256(canonical_json(payload)||nonce)";
1225
+ /** When the hash was frozen. Always strictly before kickoff: a pick that reaches kickoff unsealed stays unsealed forever, because a seal written after the game started would be a backdated proof. */
1226
+ sealed_at: string;
1227
+ /** When outcome was LAST written to a settled value, or null when that instant is unknown. It moves with a corrected market re-mapping an already-settled pick, while commitment_hash stays untouched -- which is how a mirror that keeps history sees a correction. */
1228
+ resolved_at: string | null;
1229
+ /** The frozen provider kickoff in the canonical payload form: whole seconds, UTC, literal Z. This exact string reappears inside payload.kickoff when the pick opens. */
1230
+ kickoff: string;
1231
+ payload: PickOfTheDayCommitmentPayload;
1232
+ /** How the pick settled. Never pending: a pending pick is a sealed entry. */
1233
+ outcome: "win" | "loss" | "void";
1234
+ /** Frozen matchup, for a reader. */
1235
+ matchup: string;
1236
+ /** Frozen canonical sport bucket used for selection calibration (Basketball, MMA), not the exact public league identity; the archive owns that. */
1237
+ category: string;
1238
+ /** The pick's public page. */
1239
+ permalink: string;
1240
+ };
1241
+ /** A published pick that has not settled. Carries the commitment and nothing that states a side or a price: no nonce, no payload, no outcome. Publishable the instant the pick releases. */
1242
+ export type PickOfTheDayLedgerSealedEntry = {
1243
+ state: "sealed";
1244
+ /** ET product day the pick belongs to (YYYY-MM-DD). */
1245
+ pick_date: string;
1246
+ /** 1-based daily slot within the product day. */
1247
+ pick_rank: number;
1248
+ /** sha256(canonical_json(payload) || nonce), lowercase hex, no 0x prefix. Publishable the moment the pick releases: without the nonce it is not invertible. */
1249
+ commitment_hash: string;
1250
+ /** The construction the hash was taken with, stated in the response so a verifier never has to guess the serialization. */
1251
+ commitment_algo: "sha256(canonical_json(payload)||nonce)";
1252
+ /** When the hash was frozen. Always strictly before kickoff: a pick that reaches kickoff unsealed stays unsealed forever, because a seal written after the game started would be a backdated proof. */
1253
+ sealed_at: string;
1254
+ /** The frozen provider kickoff in the canonical payload form: whole seconds, UTC, literal Z. This exact string reappears inside payload.kickoff when the pick opens. */
1255
+ kickoff: string;
1256
+ /** The pick's public page. */
1257
+ permalink: string;
1258
+ };
1259
+ /** A published pick with no commitment: it predates the scheme, or it reached kickoff unsealed. Nothing here is evidence of WHEN the pick was made. It is emitted rather than skipped, because a ledger with holes where the unprovable picks were would silently flatter the record. Once the pick settles, payload names its market, side and price, so the outcome can still be checked against the market's own resolution. */
1260
+ export type PickOfTheDayLedgerUncommittedEntry = {
1261
+ state: "uncommitted";
1262
+ /** ET product day the pick belongs to (YYYY-MM-DD). */
1263
+ pick_date: string;
1264
+ /** 1-based daily slot within the product day. */
1265
+ pick_rank: number;
1266
+ /** Always true: this pick has no commitment and never will. */
1267
+ pre_commitment: true;
1268
+ /** How the pick settled, or pending. */
1269
+ outcome: "pending" | "win" | "loss" | "void";
1270
+ /** Frozen matchup, for a reader. */
1271
+ matchup: string;
1272
+ /** Frozen canonical sport bucket used for selection calibration (Basketball, MMA), not the exact public league identity; the archive owns that. */
1273
+ category: string;
1274
+ /** When outcome was LAST written to a settled value, or null when that instant is unknown. It moves with a corrected market re-mapping an already-settled pick, while commitment_hash stays untouched -- which is how a mirror that keeps history sees a correction. */
1275
+ resolved_at: string | null;
1276
+ /** The pick's market, side and price once it has settled; null while it is pending, and null for a settled pick whose stored row lacks one of these columns. Not hashed: nothing was committed over these values, which is what pre_commitment: true says. */
1277
+ payload: PickOfTheDayUncommittedPayload | null;
1278
+ /** The pick's public page. */
1279
+ permalink: string;
1280
+ };
1281
+ /** A settled uncommitted pick's market, side and price. The same eight fields as PickOfTheDayCommitmentPayload, in the same key order, so a settled pick's side and price sit under payload whatever the entry's state. It is NOT a commitment: no hash was taken over it before the game, and it proves nothing about when the pick was made. */
1282
+ export type PickOfTheDayUncommittedPayload = {
1283
+ /** Frozen pre-game price of the backed side, 0..1, as the plain decimal text of the stored NUMERIC at full stored precision, trailing zeros included -- rendered exactly as the commitment payload renders it. */
1284
+ backed_price: string;
1285
+ /** Provider condition id of the backed market. */
1286
+ condition_id: string;
1287
+ /** Frozen provider kickoff, UTC, literal Z; null when no kickoff was frozen. Whole seconds render exactly as the commitment payload does; a sub-second instant keeps its fraction rather than being truncated, since nothing here is hashed. */
1288
+ kickoff: string | null;
1289
+ /** ET product day (YYYY-MM-DD). */
1290
+ pick_date: string;
1291
+ /** Index of the backed outcome within the market. */
1292
+ pick_outcome_index: 0 | 1;
1293
+ /** Frozen display label of the backed outcome. */
1294
+ pick_outcome_label: string;
1295
+ /** 1-based daily slot. */
1296
+ pick_rank: number;
1297
+ /** Provider platform. */
1298
+ platform: string;
1299
+ };
985
1300
  /** Provider-first sports context for a Pick of the Day market: team crests, league branding, and live score. Team logos and league logo are provider-owned (Polymarket /teams crests for clubs, country flags for national teams and tennis players); no local derivation. */
986
1301
  export type PickSportsContext = {
987
1302
  /** League or competition display name (e.g. "Premier League"). */
988
- league_name?: string | null;
1303
+ league_name: string | null;
989
1304
  /** Provider-owned event taxonomy from Gamma eventMetadata, joined in league · serie · tournament order with blanks and case-insensitive duplicates removed. Separate from league_name; omitted when the provider does not supply the metadata. */
990
- competition_label?: string | null;
1305
+ competition_label?: string;
991
1306
  /** League logo URL (provider-owned). */
992
- league_logo?: string | null;
1307
+ league_logo: string | null;
993
1308
  /** The team mapped to the market's YES outcome, or the parent-event home/first team when event_matchup is true. */
994
- yes_team?: PickSportsTeam;
1309
+ yes_team: PickSportsTeam;
995
1310
  /** The team mapped to the market's NO outcome, or the parent-event away/second team when event_matchup is true. */
996
- no_team?: PickSportsTeam;
997
- /** Provider game identifier (Polymarket Gamma gameId); omitted when null. */
998
- game_id?: number | null;
1311
+ no_team: PickSportsTeam;
1312
+ /** Provider game identifier (Polymarket Gamma gameId); omitted when the provider supplies none. */
1313
+ game_id?: number;
999
1314
  /** Always present. True when the two teams are the parent-event match identity for a teamless binary leg (e.g. a draw, totals, or prop market), not the market's own outcomes. */
1000
1315
  event_matchup: boolean;
1001
1316
  /** Present only alongside event_matchup: the event team the binary leg is about (provider group_item_title matched to a matchup team, e.g. Belgium for "Will Belgium win?"), i.e. the winner on a Yes resolution. Omitted for teamless legs (draw, totals, prop). */
1002
1317
  event_subject_team?: PickSportsTeam;
1003
1318
  /** The two teams as a single whole-game label, joined "<home> – <away>" (en-dash) in provider display order (e.g. "Portugal – Uzbekistan"). Composed server-side from the provider team names (no title/slug parsing). Present when both teams resolve a name; omitted for single-subject, teamless, or non-two-team contexts. */
1004
- matchup_title?: string | null;
1319
+ matchup_title?: string;
1005
1320
  };
1006
1321
  /** A single sports team or competitor in a Pick of the Day market's sports context. Identity and score fields are provider-owned and nullable. The structured score fields (`sets`, `format`, `sets_won`) and the tennis fields (`headshot`, `tour`) are backend-owned and are OMITTED rather than null when they do not apply, so a consumer must treat an absent key and a null the same way. */
1007
1322
  export type PickSportsTeam = {
1008
1323
  /** Team display label as it appears on the market outcome (e.g. "Portugal"). */
1009
- label?: string | null;
1324
+ label: string | null;
1010
1325
  /** Abbreviated team label (e.g. "POR"). */
1011
- short_label?: string | null;
1326
+ short_label: string | null;
1012
1327
  /** Full team or competitor name (e.g. "Portugal national football team"). */
1013
- full_name?: string | null;
1328
+ full_name: string | null;
1014
1329
  /** Provider team identifier (Polymarket /teams id). */
1015
- provider_id?: number | null;
1330
+ provider_id: number | null;
1016
1331
  /** Team crest or flag URL. Provider-owned for most teams (Polymarket /teams crest for clubs, country flag for national teams and tennis players). A club with a vendored crest carries it instead, served same-origin as a relative path (`/api/sports/team-logos/{league}/{abbr}.svg?v=<content hash>` or `.png`, resolve it against this server): every NFL and WNBA team, whose provider asset is a text tile, and the soccer clubs whose provider asset is an empty object. */
1017
- logo?: string | null;
1332
+ logo: string | null;
1018
1333
  /** Team brand color as a hex string (provider-owned). */
1019
- color?: string | null;
1334
+ color: string | null;
1020
1335
  /** Win-loss record as a display string (e.g. "12-4"). */
1021
- record?: string | null;
1336
+ record: string | null;
1022
1337
  /** Live or final score as a display string when the game is in play or settled. */
1023
- score?: string | null;
1338
+ score: string | null;
1024
1339
  /** Tennis player headshot URL, served same-origin. Present only for a tennis competitor the headshot resolver matched; absent for team sports and for unmatched players, where `logo` stays the fallback. */
1025
- headshot?: string | null;
1340
+ headshot?: string;
1026
1341
  /** Tennis tour this competitor belongs to. Present for every tennis entry whether or not `headshot` resolved, so a consumer can tell a tennis player with no photo from a non-tennis team. Absent for every other sport. Only `atp` and `wta` name a gender; the ITF World Tennis Tour runs men's and women's events and the provider does not say which, so `itf` means tennis with gender unknown. */
1027
1342
  tour?: "atp" | "wta" | "itf";
1028
1343
  /** Per-set score cells for this side, in set order. Backend-owned: render these rather than parsing `score`. Omitted entirely when the provider score is not a structured multi-set match or could not be parsed, so an absent array and an empty one carry the same meaning. */
1029
1344
  sets?: ScoreCell[];
1030
1345
  format?: ScoreFormat;
1031
1346
  /** Completed sets won by this side. Present only when both sides expose the same set columns, so a partially parsed scoreline reports no tally rather than a misleading one. */
1032
- sets_won?: number | null;
1347
+ sets_won?: number;
1033
1348
  };
1034
1349
  /** Field-level trust metadata for the full Pick of the Day payload. Present on the full shape only (omitted on the teaser and the no-pick state, because whether a specialist backs the pick is itself backed-side evidence). Unlike TraderTrust it is not gated behind expand=trust: it carries one member on an endpoint that returns a single object per day. */
1035
1350
  export type PickTrust = {
@@ -1061,33 +1376,33 @@ export type Position = {
1061
1376
  /** Binary outcome side. Non-binary positions are not surfaced on V1. */
1062
1377
  side: "YES" | "NO";
1063
1378
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets). */
1064
- token_id?: string | null;
1379
+ token_id: string | null;
1065
1380
  /** Live share count from the wallet_positions mirror. */
1066
1381
  shares: number;
1067
1382
  /** Volume-weighted entry price for this leg. */
1068
- avg_price?: number | null;
1383
+ avg_price?: number;
1069
1384
  /** Current mark-to-market value in USD (always non-null on V1 — pre-reconcile rows are excluded). */
1070
1385
  current_value_usd: number;
1071
- initial_value_usd?: number | null;
1386
+ initial_value_usd?: number;
1072
1387
  /** Unrealized P&L for the open position (Polymarket `cashPnl`). */
1073
- cash_pnl?: number | null;
1388
+ cash_pnl?: number;
1074
1389
  /** Closed-leg P&L rolled up (Polymarket `realizedPnl`). */
1075
- realized_pnl?: number | null;
1390
+ realized_pnl?: number;
1076
1391
  /** Max updated_at across mirror legs for this pair. */
1077
- last_reconciled_at?: string | null;
1392
+ last_reconciled_at?: string;
1078
1393
  /** Backend-computed staleness bucket derived from last_reconciled_at. */
1079
1394
  freshness: "fresh" | "refreshing" | "stale" | "unknown";
1080
1395
  trader: {
1081
1396
  /** Prefixed ID (`trd_...`). */
1082
1397
  id: string;
1083
1398
  address: string;
1084
- username?: string | null;
1399
+ username?: string;
1085
1400
  grade?: "S" | "A" | "B" | "C" | "D" | "F";
1086
1401
  /** Percentage 0-100. */
1087
- win_rate?: number | null;
1088
- pnl?: number | null;
1089
- markets?: number | null;
1090
- wallet_age_days?: number | null;
1402
+ win_rate?: number;
1403
+ pnl?: number;
1404
+ markets?: number;
1405
+ wallet_age_days?: number;
1091
1406
  /** True when 0xinsider first recorded the wallet within the new-wallet threshold (30 days). This public V1 field is first-seen recency, not the wallet's on-chain age. */
1092
1407
  is_new_wallet: boolean;
1093
1408
  };
@@ -1096,13 +1411,13 @@ export type Position = {
1096
1411
  id: string;
1097
1412
  condition_id: string;
1098
1413
  title: string;
1099
- slug?: string | null;
1100
- event_slug?: string | null;
1414
+ slug?: string;
1415
+ event_slug?: string;
1101
1416
  /** Provider-backed market_canonical category. */
1102
- category?: string | null;
1417
+ category?: string;
1103
1418
  /** Provider-reported outcome label (e.g. team name for sports). Separate from `side` because provider labels can diverge from the binary Yes/No axis. */
1104
- outcome_label?: string | null;
1105
- end_date?: string | null;
1419
+ outcome_label?: string;
1420
+ end_date?: string;
1106
1421
  };
1107
1422
  };
1108
1423
  export type PositionTimelineEvent = {
@@ -1114,7 +1429,7 @@ export type PositionTimelineEvent = {
1114
1429
  action: "buy" | "sell";
1115
1430
  outcome_side: "yes" | "no";
1116
1431
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets). */
1117
- token_id?: string | null;
1432
+ token_id: string | null;
1118
1433
  /** Signed share delta (+ on buy, − on sell). */
1119
1434
  amount_delta: number;
1120
1435
  /** Fill price in USDC per share, in [0,1]. */
@@ -1170,7 +1485,7 @@ export type RadarFlag = {
1170
1485
  trader: {
1171
1486
  id: string;
1172
1487
  address: string;
1173
- username?: string | null;
1488
+ username: string | null;
1174
1489
  };
1175
1490
  market: {
1176
1491
  id: string;
@@ -1180,13 +1495,13 @@ export type RadarFlag = {
1180
1495
  };
1181
1496
  scores: {
1182
1497
  /** Null because the live scorer does not record this component. */
1183
- timing?: number | null;
1498
+ timing: number | null;
1184
1499
  /** Null because the live scorer does not record this component. */
1185
- edge?: number | null;
1500
+ edge: number | null;
1186
1501
  /** Numeric evidence.size when recorded; otherwise null. */
1187
- size?: number | null;
1502
+ size: number | null;
1188
1503
  /** Numeric evidence.fresh when recorded; otherwise null. */
1189
- fresh_wallet?: number | null;
1504
+ fresh_wallet: number | null;
1190
1505
  };
1191
1506
  /** Stored whale_alerts.suspicion_signals JSON from the scorer. */
1192
1507
  evidence: unknown;
@@ -1194,44 +1509,45 @@ export type RadarFlag = {
1194
1509
  created_at: string;
1195
1510
  };
1196
1511
  export type ReportPayload = {
1197
- total_whale_trades?: number | null;
1198
- total_whale_volume?: number | null;
1199
- biggest_trade_size?: number | null;
1200
- active_traders?: number | null;
1201
- top_whale_trades?: ({
1512
+ total_whale_trades: number | null;
1513
+ total_whale_volume: number | null;
1514
+ biggest_trade_size: number | null;
1515
+ active_traders: number | null;
1516
+ top_whale_trades: ({
1202
1517
  /** Provider outcome label for the traded side. */
1203
- outcome?: string | null;
1518
+ outcome: string | null;
1204
1519
  /** Trade direction (BUY or SELL), not the outcome side. */
1205
- side?: string | null;
1520
+ side: string | null;
1206
1521
  /** Market title. */
1207
- title?: string | null;
1522
+ title: string | null;
1208
1523
  /** Trade size in USD. */
1209
- size?: number | null;
1524
+ size: number | null;
1210
1525
  /** Trade price in provider [0, 1] units. */
1211
- price?: number | null;
1526
+ price: number | null;
1212
1527
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the traded outcome; null when unavailable (e.g. unsynced markets). */
1213
- token_id?: string | null;
1528
+ token_id: string | null;
1214
1529
  /** Whale trade id. */
1215
- id?: number | null;
1530
+ id: number | null;
1216
1531
  /** Trade timestamp (UTC). */
1217
- trade_time?: string | null;
1532
+ trade_time: string | null;
1218
1533
  /** Provider market category. */
1219
- market_category?: string | null;
1534
+ market_category: string | null;
1220
1535
  /** Venue: polymarket. */
1221
- platform?: string | null;
1536
+ platform: string | null;
1222
1537
  /** Trader display name, when known. */
1223
- name?: string | null;
1538
+ name: string | null;
1224
1539
  /** Trader pseudonym, when no display name is known. */
1225
- pseudonym?: string | null;
1540
+ pseudonym: string | null;
1226
1541
  /** Trader grade (S-F) at snapshot time. */
1227
- trader_grade?: string | null;
1542
+ trader_grade: string | null;
1228
1543
  })[] | null;
1229
- categories?: Record<string, unknown>[] | null;
1230
- grade_distribution?: Record<string, unknown>[] | null;
1544
+ categories: Record<string, unknown>[] | null;
1545
+ grade_distribution: Record<string, unknown>[] | null;
1231
1546
  };
1232
1547
  export type ReportReconciliation = {
1233
1548
  volume_kind: "local_whale_activity_volume";
1234
- whale_volume_source: "whale_alerts.usdc_notional_num";
1549
+ /** Where the whale volume in this report is read from: the column name `whale_alerts.usdc_notional_num`, followed in parentheses by the reconciliation note the server attaches to it. The server has always sent the note with the name, so this is not a bare constant; match on the prefix, not the whole string. */
1550
+ whale_volume_source: string;
1235
1551
  notes: string;
1236
1552
  };
1237
1553
  export type ReportSnapshot = {
@@ -1249,17 +1565,17 @@ export type ReportSourceRange = {
1249
1565
  timezone: "UTC";
1250
1566
  };
1251
1567
  export type ResponseMeta = {
1252
- /** Unique request ID (req_ prefix). */
1568
+ /** Unique request ID (req_ prefix). The same value as the X-Request-Id response header, the request's usage accounting row and its log lines. */
1253
1569
  request_id: string;
1254
1570
  cached: boolean;
1255
1571
  /** Cache age in seconds. Omitted when the response was not cached, and also when it was cached but its age cannot be established (an entry stored before its cache carried a computed instant). Never a placeholder: an unknown age is reported as no value rather than as the cache TTL. */
1256
- cache_age_s?: number | null;
1572
+ cache_age_s?: number;
1257
1573
  /** Advisory request weight (relative compute cost). 1 for simple reads; higher for heavier endpoints. Not a credit/price. */
1258
1574
  cost: number;
1259
1575
  /** Committed PostgreSQL-owned leaderboard generation for the returned rows and cursor. Present on GET /api/v1/leaderboard; omitted on endpoints that do not read this ranking. */
1260
- ranking_generation?: number | null;
1576
+ ranking_generation?: number;
1261
1577
  /** Authoritative RFC3339 timestamp from cache_generations.updated_at for ranking_generation. It is read in the same repeatable-read snapshot as the leaderboard rows and is not request time, cache write time, or row insertion order. */
1262
- ranking_as_of?: string | null;
1578
+ ranking_as_of?: string;
1263
1579
  /** Which path produced the team-directional read on this response. Only present on endpoints that compute one (today: GET /api/v1/sports-edge-signals). "live" means the read RAN. "degraded" means it FAILED, so nothing was measured and the ranking fell back to raw conviction. The flag describes the READ, not its consequence: a read that ran and found nothing groupable also leaves the directional fields null, and that is honestly "live" -- the per-signal nulls already say "nothing to enrich here", so this snapshot-level flag carries only what they cannot, namely whether the read ran at all. A degraded response is cached on the shorter degraded TTL so it self-heals. Reported SEPARATELY from ranking_source because the two degradations are independent -- a smart-money DB miss weakens the ranking DATA, a directional failure removes a ranking WEIGHT -- and a consumer down-weighting a degraded response needs to know which input it lost. Omitted on endpoints that compute no directional read. */
1264
1580
  directional_source?: "live" | "degraded";
1265
1581
  /** Which ranking-data path produced this response. Only present on endpoints that can degrade a ranking (today: GET /api/v1/sports-edge-signals). "live" is the normal path (the current holder pile from the provider batch); "db_only" is the degraded fallback (a truthful but weaker trader_markets ranking) served when the live sharp-money ranking batch is unavailable (a smart-money DB read failure, not a Polymarket outage) and cached on a shorter TTL, so a consumer can down-weight or skip it. Omitted on endpoints that never degrade. */
@@ -1318,7 +1634,7 @@ export type SmartMoneyFlowMarket = {
1318
1634
  net_flow_usd: number;
1319
1635
  direction: "YES" | "NO";
1320
1636
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets). */
1321
- token_id?: string | null;
1637
+ token_id: string | null;
1322
1638
  whale_trade_count: number;
1323
1639
  buy_volume_usd: number;
1324
1640
  sell_volume_usd: number;
@@ -1328,7 +1644,7 @@ export type SmartMoneyFlowMarket = {
1328
1644
  net_flow_usd: number;
1329
1645
  direction: "YES" | "NO";
1330
1646
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets). */
1331
- token_id?: string | null;
1647
+ token_id: string | null;
1332
1648
  whale_trade_count: number;
1333
1649
  buy_volume_usd: number;
1334
1650
  sell_volume_usd: number;
@@ -1336,17 +1652,28 @@ export type SmartMoneyFlowMarket = {
1336
1652
  timeframe: string;
1337
1653
  };
1338
1654
  export type SnapshotCompleteness = {
1655
+ /** complete only on a final body (snapshot.status final). partial for a live range and for a closed range whose body was read before final_after; reason says which. empty when the range has no whale activity. */
1339
1656
  status: "complete" | "partial" | "empty";
1340
1657
  reason: string;
1341
1658
  expected_days: number;
1342
1659
  covered_days_with_whale_activity: number;
1343
1660
  };
1344
1661
  export type SnapshotState = {
1345
- /** Immutable content version for this report identity. */
1662
+ /** Immutable content version for a durable report identity; 0 for an ephemeral explicit weekly from/to range. */
1346
1663
  version: number;
1664
+ /** durable for canonical daily, ISO-week, and monthly snapshot identities; ephemeral for explicit weekly from/to ranges, which are recomputed within a bounded 31-day window and never persisted. */
1665
+ storage: "durable" | "ephemeral";
1666
+ /** final only for a body whose source read started at or after final_after (the UTC close of the range plus the whale-trade ingestion budget). rolling for a live range and for a closed range still inside that budget: such a body refreshes every five minutes, is rebuilt once after final_after, and is then frozen. Before 2026-09-22 a closed range read final from the calendar alone, even for a body built before the range ended (#16225). */
1347
1667
  status: "final" | "rolling";
1348
1668
  generated_at: string;
1349
- mutable_until?: string | null;
1669
+ /** For a rolling body, the UTC date on which a final body can first be built (the date of final_after); null once final. */
1670
+ mutable_until: string | null;
1671
+ /** Whether the source range has ended on the UTC calendar. Closing is not finality: a closed range is rolling until final_after. */
1672
+ period_closed: boolean;
1673
+ /** The instant a source read must start at or after to produce a final body: the range's UTC close plus 7,530 s, the whale-trade ingestion budget (p95 block lag gate plus the projection retry budget). */
1674
+ final_after: string;
1675
+ /** When this body's source read started, the clock finality is judged on. null for a body stored before that clock was recorded. */
1676
+ source_read_started_at: string | null;
1350
1677
  };
1351
1678
  /** Per-sport accountable funnel for the full observation snapshot, returned on every page. */
1352
1679
  export type SportsEdgeFunnelReport = {
@@ -1425,21 +1752,21 @@ export type SportsEdgeSignal = {
1425
1752
  /** UTC time at which the immutable signal snapshot was computed. Every row from one snapshot shares this value; it is not provider market creation time and is not rewritten at request time. */
1426
1753
  signal_created_at: string;
1427
1754
  /** Polymarket CLOB token id (ERC1155 asset id, decimal string) for the PILED outcome; null when unavailable. */
1428
- token_id?: string | null;
1755
+ token_id: string | null;
1429
1756
  /** Canonical sport bucket (e.g. Basketball, Tennis); null when the raw category has no canonical mapping. */
1430
- category?: string | null;
1757
+ category: string | null;
1431
1758
  /** Raw provider category as stored (e.g. NBA, EPL). */
1432
- raw_category?: string | null;
1433
- title?: string | null;
1434
- event_slug?: string | null;
1759
+ raw_category: string | null;
1760
+ title: string | null;
1761
+ event_slug: string | null;
1435
1762
  /** Kickoff (UTC). In the future at SNAPSHOT time and within the requested horizon; because the response is served from a shared snapshot cached up to the ~180s TTL, a served kickoff can be up to ~180s in the past relative to the response time. Not a live guarantee that the game has not yet started. */
1436
- game_start_time?: string | null;
1763
+ game_start_time: string | null;
1437
1764
  /** Nullable provider-backed piled-outcome display label. When provider group context is unavailable, it may remain a bare Yes/No/Over/Under; do not use it alone as participant identity. */
1438
- piled_side?: string | null;
1765
+ piled_side: string | null;
1439
1766
  /** Provider binary-column selector: 0 selects outcome_yes/token_id_yes; 1 selects outcome_no/token_id_no. It does not identify home/away or a participant. Use piled_side together with title/event context for display. */
1440
1767
  piled_outcome_index: number;
1441
1768
  /** Piled-side dollar concentration backed_usd / (yes_usd + no_usd), in (0.5, 1] for a real pile; null when there is no sharp USD. */
1442
- sharp_pct?: number | null;
1769
+ sharp_pct: number | null;
1443
1770
  /** Raw piled-side sharp-money USD. */
1444
1771
  backed_sharp_usd: number;
1445
1772
  /** S-grade graded holders on the piled side. */
@@ -1451,23 +1778,23 @@ export type SportsEdgeSignal = {
1451
1778
  /** Piled-side graded holder count (s_count + a_count + b_count). */
1452
1779
  graded_holders: number;
1453
1780
  /** Best grade present on the piled side; null when none. */
1454
- top_grade?: "S" | "A" | "B";
1781
+ top_grade: "S" | "A" | "B" | null;
1455
1782
  /** Canonical sharp-money score (yes_usd - no_usd)/(yes_usd + no_usd) in [-1, 1] (piled-yes positive, piled-no negative); a lower-order ranking tiebreak (after directional_rank_score and conviction_score). */
1456
- smart_score?: number | null;
1783
+ smart_score: number | null;
1457
1784
  /** Market volume (USD). */
1458
- volume?: number | null;
1785
+ volume: number | null;
1459
1786
  /** Aggregate recent flow direction on the market; null when unavailable. */
1460
- net_side?: "BUY" | "SELL";
1787
+ net_side: "BUY" | "SELL" | null;
1461
1788
  /** Grade-weighted pile score (5*s + 4*a + 3*b) * sharp_pct; the raw conviction input to the ranking (see directional_rank_score). */
1462
1789
  conviction_score: number;
1463
1790
  /** Piled-side graded holders read one-way: their fresh open legs across the signal game's markets (cross-market within the one game; moneyline+spread family only) all back the same team, or, when the market's holder scan was complete, Polymarket's currentValue shows no opposite leg on this market worth 10% of the backed leg and no fresh leg opposes it. Null when the directional read was not computed (no groupable game, no holder-level data on this ranking path, or the enrichment read failed) or classified nobody. */
1464
- one_way_holder_count?: number | null;
1791
+ one_way_holder_count: number | null;
1465
1792
  /** Piled-side graded holders classified HEDGED across the game by fresh legs (they back two or more distinct teams). A wallet long both outcomes of this market is not one-way and not counted here. Null when the directional read was not computed or classified nobody. */
1466
- hedged_holder_count?: number | null;
1793
+ hedged_holder_count: number | null;
1467
1794
  /** Piled-side graded USD held by one-way wallets (share-weighted allocation of backed_sharp_usd). Null when the directional read was not computed or classified nobody. */
1468
- one_way_graded_usd?: number | null;
1795
+ one_way_graded_usd: number | null;
1469
1796
  /** One-way fraction of the piled graded dollars, in [0, 1] -- the metric orthogonal to sharp_pct. Stale, unknown, hedged, and two-sided dollars dilute it toward zero (conservative). Null when the directional read was not computed or classified nobody. */
1470
- directional_confidence?: number | null;
1797
+ directional_confidence: number | null;
1471
1798
  /** The ranking key, descending: conviction_score * (1 + 0.25 * directional_confidence). Equals conviction_score when the directional read is null/zero, so signals without the read rank exactly as before. */
1472
1799
  directional_rank_score: number;
1473
1800
  category_skill: SportsEdgeSignalCategorySkill;
@@ -1525,35 +1852,36 @@ export type Trader = {
1525
1852
  /** Prefixed ID (trd_...). */
1526
1853
  id: string;
1527
1854
  address: string;
1528
- username?: string | null;
1855
+ username?: string;
1529
1856
  grade?: "S" | "A" | "B" | "C" | "D" | "F";
1530
- /** Hot-streak tier (trailing-7d cross-sectional percentile); a separate axis from the all-time grade. Null when no recent activity. */
1857
+ /** Hot-streak tier (trailing-7d cross-sectional percentile); a separate axis from the all-time grade. Omitted when there is no recent activity. */
1531
1858
  streak_tier?: "hot" | "rising" | "neutral" | "cooling" | "cold";
1532
- score?: number | null;
1533
- rank?: number | null;
1859
+ score?: number;
1860
+ rank?: number;
1534
1861
  pnl: {
1535
- total?: number | null;
1862
+ total?: number;
1536
1863
  /** For pnl.realized, expand=trust marks a matching native accounting snapshot as computed: native Polymarket realized P&L plus credited maker and taker rebates, with fees already included. The exact numeric value is truncated toward zero to cents before conversion to a JSON number. Without a matching native accounting snapshot, pnl.realized is omitted and its trust metadata is unavailable. Raw total P&L is never substituted for realized P&L. */
1537
- realized?: number | null;
1538
- unrealized?: number | null;
1539
- /** DEPRECATED, always null. The local pnl_7d rollup over-counted P&L (#5416 class) and is no longer emitted. Read the provider-native weekly window from GET /api/trader/{address}/profile-summary instead. */
1540
- last_7d?: number | null;
1541
- /** DEPRECATED, always null. The local pnl_30d rollup over-counted P&L (#5416 class) and is no longer emitted. Read the provider-native monthly window from GET /api/trader/{address}/profile-summary instead. */
1542
- last_30d?: number | null;
1864
+ realized?: number;
1865
+ unrealized?: number;
1866
+ /** DEPRECATED, never sent. The local pnl_7d rollup over-counted P&L (#5416 class) and is no longer emitted. Read the provider-native weekly window from GET /api/trader/{address}/profile-summary instead. */
1867
+ last_7d?: number;
1868
+ /** DEPRECATED, never sent. The local pnl_30d rollup over-counted P&L (#5416 class) and is no longer emitted. Read the provider-native monthly window from GET /api/trader/{address}/profile-summary instead. */
1869
+ last_30d?: number;
1543
1870
  };
1544
1871
  stats: {
1545
- markets_traded?: number | null;
1546
- win_rate?: number | null;
1547
- daily_win_rate?: number | null;
1548
- total_volume?: number | null;
1872
+ markets_traded?: number;
1873
+ win_rate?: number;
1874
+ daily_win_rate?: number;
1875
+ /** Full-history both-sides USD cash volume from Polymarket user-volume. Omitted without a verified observation; never leaderboard shares. Volume freshness is unknown in this DTO and does not use synced_at. */
1876
+ total_volume?: number;
1549
1877
  };
1550
1878
  strategy?: {
1551
1879
  strategy_type?: string;
1552
- description?: string | null;
1553
- confidence?: number | null;
1554
- } | null;
1555
- /** Per-category performance breakdown (expand=categories or expand[]=categories). Omitted unless expanded. Object keyed by category name; each value is the precomputed trader_rankings.category_ranks payload (rank, total_in_category, total_pnl, scaled_total_pnl, n_markets, wins, losses, win_rate; scaled_total_pnl is a legacy alias that currently equals total_pnl). Pass-through DB JSON: keys and value shape are DB-owned, so the inner shape is intentionally unconstrained and may carry additional compatibility fields. */
1556
- category_strengths?: Record<string, unknown> | null;
1880
+ description?: string;
1881
+ confidence?: number;
1882
+ };
1883
+ /** Per-category performance breakdown (expand=categories or expand[]=categories). Omitted unless expanded. Object keyed by category name; each value is the precomputed trader_rankings.category_ranks payload (rank, total_in_category, total_pnl, scaled_total_pnl, n_markets, wins, losses, win_rate; scaled_total_pnl is a legacy alias that currently equals total_pnl). BASIS: the calibration sample, which admits a position only above a 20 USD notional floor and with a chosen-side entry price strictly inside (0,1), because the ranks and the calibration edge derived from it depend on both rules. That is a different sample from GET /api/v1/trader/{address}/categories, which counts every settled market at any size, and the two differ in both directions. Measured on production 2026-09-22 over the 122,497 wallet-category pairs with at least 20 decided markets on both bases: the floored rate was higher in 56.5% of pairs, lower in 34.5% and equal in 9.0%, median +0.6 points, p10 -4.6, p90 +9.8, and 14.0% of pairs differ by 10 points or more. The difference is not only small positions: on a 1-in-250 wallet sample the same day, admitted markets won 56.6% while markets dropped by the notional floor alone won 45.2% and markets dropped by the entry-price rule alone won 48.7%. n_markets counts every admitted market including the ones that resolved at exactly zero P&L, so it is not the denominator of win_rate: it differed from wins + losses in 15.8% of pairs with at least 5 decided markets. The two tables also run on different clocks, this one updated incrementally and that route rebuilt daily, so a same-day read can differ on timing alone. Use this for rank context and that route for the wallet's plain record. Pass-through DB JSON: keys and value shape are DB-owned, so the inner shape is intentionally unconstrained and may carry additional compatibility fields. */
1884
+ category_strengths?: Record<string, unknown>;
1557
1885
  /** Curated advanced risk/performance metrics (expand=quant_metrics or expand[]=quant_metrics). Omitted unless expanded and backed by a computed row strictly under six hours old; a missing row, NULL computed_at, or age of exactly six hours or more is stale and omitted. Provider-input changes may intentionally lag inside the bounded six-hour window. When present, all listed fields are present (each is a number or null); null means insufficient trade history and must not be treated as 0. The fixed field shape is unchanged. */
1558
1886
  quant_metrics?: {
1559
1887
  /** Composite skill score, 0-100. smart_score = clamp(0, 100, 30*sharpe_percentile_fraction + 20*profit_factor_percentile_fraction + 20*edge_consistency_percentile_fraction + 10*min(1, return_on_capital/2) + 10*equity_smoothness + 10*(1 - min(1, asset_concentration))). Higher is better. null when insufficient history. */
@@ -1574,17 +1902,45 @@ export type Trader = {
1574
1902
  pf_percentile: number | null;
1575
1903
  /** Cross-sectional percentile rank of edge consistency versus all traders, 0-100. null when insufficient history. */
1576
1904
  consistency_percentile: number | null;
1577
- } | null;
1578
- last_active?: string | null;
1579
- synced_at?: string | null;
1905
+ };
1906
+ last_active?: string;
1907
+ synced_at?: string;
1580
1908
  /** synced, unknown, or pending. */
1581
- sync_status?: string | null;
1909
+ sync_status?: string;
1582
1910
  /** Field-level trust metadata. Present only when expand=trust or expand[]=trust is requested. */
1583
1911
  trust?: TraderTrust;
1584
1912
  /** Current evidence for observed and known categories (expand=categories or expand[]=categories). Omitted unless expanded. Includes insufficient, stale, unknown and degraded rows; absence of a category is not proof of skill. The global grade is unchanged. */
1585
1913
  category_records?: CategorySkillV2[];
1586
1914
  category_skill_model?: CategorySkillModelReadiness;
1587
1915
  };
1916
+ export type TraderCategoryRecord = {
1917
+ /** Canonical category bucket, for example Soccer, Esports, Tennis. Esports is one bucket, and the Esports record carries its per-game records in games. */
1918
+ category: string;
1919
+ /** Markets in this category the wallet closed with a profit. */
1920
+ wins: number;
1921
+ /** Markets it closed with a profit or a loss. A market that resolved at exactly zero P&L is in neither count, so this is not the wallet's market count in the category. */
1922
+ decided: number;
1923
+ /** wins / decided in [0,1], truncated to four decimals. Null when status is not_enough_data. */
1924
+ win_rate: number | null;
1925
+ /** measured: decided cleared min_decided_for_win_rate and win_rate carries the rate. not_enough_data: the counts are real but the sample is under the floor, so no percent is published. A failed read is an error response, never a status value. */
1926
+ status: "measured" | "not_enough_data";
1927
+ /** The wallet's record per esports title, busiest first. Present only on the Esports record, and only when the wallet has a settled market in at least one title; absent on every other category and on an Esports record whose markets are all in series that are not games (skin-price indices, streamer props) or carry no series. Absent means no per-game record, the same rule as an absent category. Each entry's decided is a subset of the Esports record's, read in the same statement from the same daily rebuild. */
1928
+ games?: TraderEsportsGameRecord[];
1929
+ };
1930
+ export type TraderCategoryRecords = {
1931
+ /** Prefixed trader id (trd_<wallet>). */
1932
+ id: string;
1933
+ /** Resolved wallet address, lowercased. */
1934
+ address: string;
1935
+ /** Which sample the counts come from: every settled market in the category, at any position size. category_strengths on the trader endpoint reads the floored calibration sample instead, so the two differ in both directions: measured on production 2026-09-22 over the 122,497 wallet-category pairs with at least 20 decided markets on both bases, the floored rate was higher in 56.5% of pairs and lower in 34.5%, median +0.6 points, p10 -4.6, p90 +9.8, with 14.0% of pairs 10 points apart or more. Neither corrects the other. */
1936
+ basis: "settled_markets_all_sizes";
1937
+ /** Decided markets a category needs before win_rate is served. Published so a caller can apply its own sample rule to the raw counts. */
1938
+ min_decided_for_win_rate: number;
1939
+ /** When the served records were last rebuilt (RFC3339, Z): the newest stamp among every row served, game rows included, which the daily rebuild writes in one transaction. Null when the wallet has no record at all. */
1940
+ computed_at: string | null;
1941
+ /** One entry per canonical category with at least one decided market, ordered by decided descending then category. A category with no decided market is omitted. The Esports entry carries its per-game records in games. */
1942
+ records: TraderCategoryRecord[];
1943
+ };
1588
1944
  export type TraderContext = {
1589
1945
  trader: Trader;
1590
1946
  /** Aggregate position and P&L coverage for the trader. Omitted entirely (key absent, never null) when the trader is not in the local database or native net economics is unavailable. Realized fields remain numbers when present, including a genuine zero. */
@@ -1610,9 +1966,9 @@ export type TraderContext = {
1610
1966
  /** Win rate as a percentage (0-100): resolved_wins over resolved_decided. A resolved market that settled at exactly zero realized P&L (a void, a refund, a fully hedged position) is neither a win nor a loss and is not in the denominator, the same rule the leaderboard applies; null when no resolved market was decided. */
1611
1967
  resolved_win_rate: number | null;
1612
1968
  /** Resolved markets that settled at positive realized P&L: the win-rate numerator. Additive; null only on a summary cached before the field existed. */
1613
- resolved_wins?: number | null;
1969
+ resolved_wins: number | null;
1614
1970
  /** Resolved markets that settled at a non-zero realized P&L: the win-rate denominator. At most markets_resolved; the difference is markets settled at exactly zero or with an unknown P&L. Additive; null only on a summary cached before the field existed. */
1615
- resolved_decided?: number | null;
1971
+ resolved_decided: number | null;
1616
1972
  /** RFC3339 freshness of the served OPEN-position data: the trader's latest /positions snapshot, else the last completed sync. The snapshot advances ONLY open positions, so read this as the open-position freshness clock -- the resolved/closed aggregates on this same summary (markets_resolved, resolved_win_rate) advance only on a full sync. The value is the /positions snapshot instant when one exists, so it is typically at or just before the trader-level last sync on a normal sync, and can be AFTER it while the active-view loop refreshes open positions between full syncs. This clock does not establish native accounting freshness. Always present on the wire (serialized as JSON null when the trader has neither a snapshot nor a sync); never omitted. */
1617
1973
  as_of: string | null;
1618
1974
  };
@@ -1621,16 +1977,30 @@ export type TraderContext = {
1621
1977
  /** Human-readable statement of the point-in-time snapshot semantics (data_as_of is the open-position clock -- the latest /positions snapshot, else the last completed sync; the snapshot advances only open positions, so resolved counts and win rate date to the last full sync; native realized P&L follows its accounting snapshot -- not a live feed; re-fetch for fresher data). */
1622
1978
  freshness_note: string;
1623
1979
  };
1980
+ export type TraderEsportsGameRecord = {
1981
+ /** The game, by the same name every holder chip carries in category_win_rate_game: LoL, CS2, Dota 2, Valorant, Call of Duty, Honor of Kings, Mobile Legends: Bang Bang, Overwatch, Rainbow Six Siege, Rocket League or StarCraft II. Match a chip to this row by string equality. */
1982
+ game: string;
1983
+ /** The Polymarket series slug the record is keyed on: league-of-legends, counter-strike, dota-2, valorant, call-of-duty, honor-of-kings, mobile-legends-bang-bang, overwatch, rainbow-six-siege, rocket-league or starcraft-2. The stable key; game is the label. */
1984
+ series_slug: string;
1985
+ /** Markets in this game the wallet closed with a profit. */
1986
+ wins: number;
1987
+ /** Markets in this game it closed with a profit or a loss. A subset of the parent Esports record's decided: the two are read from the same daily rebuild. */
1988
+ decided: number;
1989
+ /** wins / decided in [0,1], truncated to four decimals. Null when status is not_enough_data. */
1990
+ win_rate: number | null;
1991
+ /** The same rule as the parent record: measured when decided cleared min_decided_for_win_rate, not_enough_data when the counts are real but the sample is under the floor. A chip on a market in this game shows this row's rate when it is measured and the Esports bucket's otherwise. */
1992
+ status: "measured" | "not_enough_data";
1993
+ };
1624
1994
  export type TraderExportJob = {
1625
1995
  object: "trader_export_job";
1626
1996
  data: {
1627
1997
  job_id: number;
1628
1998
  status: "queued" | "running" | "ready" | "failed";
1629
1999
  format: "json" | "ndjson" | "csv";
1630
- total_trades?: number | null;
1631
- processed_trades?: number | null;
1632
- file_size?: number | null;
1633
- error?: string | null;
2000
+ total_trades: number | null;
2001
+ processed_trades: number | null;
2002
+ file_size: number | null;
2003
+ error: string | null;
1634
2004
  };
1635
2005
  meta: ResponseMeta;
1636
2006
  };
@@ -1646,26 +2016,26 @@ export type TraderExportSnapshot = {
1646
2016
  export type TraderPnl = {
1647
2017
  /** Prefixed trader ID (`trd_...`). */
1648
2018
  id: string;
1649
- /** RFC3339 served-freshness clock for this trader's PnL history = traders.daily_pnl_recomputed_at, when the daily_pnl read model this response is served from was last rebuilt; null when it has never been recomputed for the trader. Additive optional (not in `required`). */
1650
- freshness_at?: string | null;
2019
+ /** RFC3339 served-freshness clock for this trader's PnL history = traders.daily_pnl_recomputed_at, when the daily_pnl read model this response is served from was last rebuilt; null when it has never been recomputed for the trader. Always present, so read it as a value that can be null rather than a key that can be missing. */
2020
+ freshness_at: string | null;
1651
2021
  /** Daily cumulative-P&L series (oldest-first). */
1652
- entries: ({
2022
+ entries: {
1653
2023
  date: string;
1654
- markets_traded?: number | null;
1655
- total_volume?: number | null;
1656
- cumulative_profit?: number | null;
1657
- total_pnl?: number | null;
2024
+ markets_traded?: number;
2025
+ total_volume?: number;
2026
+ cumulative_profit?: number;
2027
+ total_pnl?: number;
1658
2028
  daily_change: number;
1659
- })[];
2029
+ }[];
1660
2030
  stats: {
1661
2031
  all: {
1662
2032
  current: number;
1663
2033
  change: number;
1664
2034
  change_pct: number;
1665
2035
  best_day: number;
1666
- best_day_date?: string | null;
2036
+ best_day_date?: string;
1667
2037
  worst_day: number;
1668
- worst_day_date?: string | null;
2038
+ worst_day_date?: string;
1669
2039
  win_days: number;
1670
2040
  loss_days: number;
1671
2041
  avg_day: number;
@@ -1676,9 +2046,9 @@ export type TraderPnl = {
1676
2046
  change: number;
1677
2047
  change_pct: number;
1678
2048
  best_day: number;
1679
- best_day_date?: string | null;
2049
+ best_day_date?: string;
1680
2050
  worst_day: number;
1681
- worst_day_date?: string | null;
2051
+ worst_day_date?: string;
1682
2052
  win_days: number;
1683
2053
  loss_days: number;
1684
2054
  avg_day: number;
@@ -1689,9 +2059,9 @@ export type TraderPnl = {
1689
2059
  change: number;
1690
2060
  change_pct: number;
1691
2061
  best_day: number;
1692
- best_day_date?: string | null;
2062
+ best_day_date?: string;
1693
2063
  worst_day: number;
1694
- worst_day_date?: string | null;
2064
+ worst_day_date?: string;
1695
2065
  win_days: number;
1696
2066
  loss_days: number;
1697
2067
  avg_day: number;
@@ -1702,9 +2072,9 @@ export type TraderPnl = {
1702
2072
  change: number;
1703
2073
  change_pct: number;
1704
2074
  best_day: number;
1705
- best_day_date?: string | null;
2075
+ best_day_date?: string;
1706
2076
  worst_day: number;
1707
- worst_day_date?: string | null;
2077
+ worst_day_date?: string;
1708
2078
  win_days: number;
1709
2079
  loss_days: number;
1710
2080
  avg_day: number;
@@ -1758,24 +2128,27 @@ export type TrendingWallet = {
1758
2128
  address: string;
1759
2129
  /** 1-based rank within the full ranked set (stable across pages). */
1760
2130
  rank: number;
1761
- username?: string | null;
2131
+ username?: string;
1762
2132
  /** Official Polymarket avatar URL (profileImage). */
1763
- profile_image_url?: string | null;
1764
- /** Real provider platform; surfaced, never coerced. Polymarket-only today. */
2133
+ profile_image_url?: string;
2134
+ /** Real provider platform; surfaced, never coerced. Polymarket only. */
1765
2135
  platform: "polymarket";
1766
2136
  /** Polymarket weekly/monthly P&L for the wallet in USD, taken from Polymarket's canonical leaderboard (data-api.polymarket.com/v1/leaderboard?timePeriod=week|month&orderBy=PNL). This is the ranking axis and the rows are returned in Polymarket's by-PNL order; it is the provider's number, not a locally summed realized-leaf total. */
1767
2137
  trending_pnl_usd: number;
1768
- window_volume_usd: number;
2138
+ /** Both-sides cash volume over the window in USD, from Polymarket GET /v2/user-volume (volume_usdc). Omitted when Polymarket served no volume for the wallet: an absent observation, never zero. Polymarket tracks volume in whole UTC days, so this window is the whole-day span covering the requested one, which is not the exact span trending_pnl_usd was scored over. */
2139
+ window_volume_usd?: number;
2140
+ /** Both-sides traded volume over the window in SHARES, from the Polymarket leaderboard row, whose own schema states the figure is never USD. Omitted when the row carried none. */
2141
+ window_volume_shares?: number;
1769
2142
  window_markets_traded: number;
1770
2143
  /** Distinct in-window UTC trade days from our trades (0 if the winner is not in our DB). */
1771
2144
  window_trade_days: number;
1772
2145
  /** All-time trader grade; a separate axis from streak_tier. Led by realized profit (the money actually banked, about 95 percent of the grade), with forecasting calibration, risk-adjusted returns, and consistency as the tie-breaker and proven-trader guardrails: any grade above C requires verified net-positive realized profit, and the top grades also require a real resolved-market track record plus a survivable drawdown. Relative, so it drifts as the cohort moves. Omitted when the trader is Unranked (fewer than 5 markets, or too little verified record to cohort-rank). */
1773
2146
  grade?: "S" | "A" | "B" | "C" | "D" | "F";
1774
- /** Hot-streak tier (trailing-7d cross-sectional percentile). Null when no recent activity. */
2147
+ /** Hot-streak tier (trailing-7d cross-sectional percentile). Omitted when there is no recent activity. */
1775
2148
  streak_tier?: "hot" | "rising" | "neutral" | "cooling" | "cold";
1776
- all_time_pnl_usd?: number | null;
1777
- all_time_score?: number | null;
1778
- last_synced?: string | null;
2149
+ all_time_pnl_usd?: number;
2150
+ all_time_score?: number;
2151
+ last_synced?: string;
1779
2152
  /** Shape-only daily P&L sparkline across the window, derived from Polymarket's documented user-pnl cumulative curve (GET /v2/user-pnl) converted to per-day deltas. It conveys the trend of the curve only and is NOT guaranteed to sum to trending_pnl_usd, which is the canonical leaderboard total. */
1780
2153
  daily_pnl_series: {
1781
2154
  date: string;
@@ -1785,13 +2158,13 @@ export type TrendingWallet = {
1785
2158
  /** Whether the described value or result set is complete for its stated contract. */
1786
2159
  export type TrustCompleteness = {
1787
2160
  status: "complete" | "partial" | "not_computed" | "not_applicable" | "unavailable";
1788
- detail?: string | null;
2161
+ detail?: string;
1789
2162
  };
1790
2163
  /** Freshness metadata for a trust-critical value. This is separate from transport cache fields in ResponseMeta. */
1791
2164
  export type TrustFreshness = {
1792
2165
  status: "fresh" | "refreshing" | "stale" | "not_live" | "unknown" | "unavailable";
1793
- as_of?: string | null;
1794
- max_age_s?: number | null;
2166
+ as_of?: string;
2167
+ max_age_s?: number;
1795
2168
  };
1796
2169
  /** Shared source/freshness/reconciliation/completeness metadata for public API values that may be cached, stale, partial, computed, or provider-unavailable. Unavailable provider values must be represented with explicit metadata instead of fabricated zeros or empty arrays. */
1797
2170
  export type TrustMetadata = {
@@ -1803,7 +2176,7 @@ export type TrustMetadata = {
1803
2176
  /** How provider-owned facts were reconciled with stored/read-model values. */
1804
2177
  export type TrustReconciliation = {
1805
2178
  status: "provider_backed" | "db_mirror" | "computed" | "partial" | "not_applicable" | "unavailable";
1806
- detail?: string | null;
2179
+ detail?: string;
1807
2180
  };
1808
2181
  /** Source metadata for a trust-critical value. Providers and DB/read models own business truth; clients should not infer missing provider facts from titles, slugs, zeros, or empty arrays. */
1809
2182
  export type TrustSource = {
@@ -1811,7 +2184,7 @@ export type TrustSource = {
1811
2184
  /** Provider, table/read-model, cache, or service that owns the value. */
1812
2185
  owner: string;
1813
2186
  /** Provider field, DB column, or computed field name when applicable. */
1814
- field?: string | null;
2187
+ field?: string;
1815
2188
  };
1816
2189
  export type UpdateWebhookRequest = {
1817
2190
  name?: string;
@@ -1838,6 +2211,24 @@ export type Usage = {
1838
2211
  reset_at: number;
1839
2212
  window_seconds: number;
1840
2213
  };
2214
+ /** The monthly request quota (#16111): where the account stands against the requests Pro includes per UTC calendar month. Reading it here spends nothing. null only when the month's count could not be read for this response. */
2215
+ monthly_quota: {
2216
+ /** Admitted requests so far this UTC calendar month. */
2217
+ used: number;
2218
+ /** Requests Pro includes per UTC calendar month. */
2219
+ limit: number;
2220
+ remaining: number;
2221
+ /** Unix seconds: the first instant of the next UTC calendar month. */
2222
+ reset_at: number;
2223
+ /** Unix seconds: from when request limit + 1 is refused for an account the quota binds. */
2224
+ enforced_from: number;
2225
+ /** Whether requests over this account's ceiling are refused right now: false before enforced_from and for an admin account. */
2226
+ binding: boolean;
2227
+ /** Pay as you go is on: requests over the quota keep answering and bill on a monthly invoice, up to ceiling. */
2228
+ pay_as_you_go: boolean;
2229
+ /** The most requests this account is admitted in a UTC calendar month once enforcement has begun: limit, or 1,000,000 with pay as you go on. null for an admin account, which no number stops. Additive since 2026-09-22. */
2230
+ ceiling: number | null;
2231
+ } | null;
1841
2232
  };
1842
2233
  meta: ResponseMeta;
1843
2234
  };
@@ -1864,6 +2255,8 @@ export type WebhookDelivery = {
1864
2255
  delivered_at?: string;
1865
2256
  /** When the next delivery attempt is due, for a delivery whose status is pending or retry. null while an attempt is in flight (processing) and once the delivery is terminal (delivered or dead_letter). */
1866
2257
  next_attempt_at: string | null;
2258
+ /** Why next_attempt_at was scheduled: receiver_retry_after for an accepted Retry-After on a 408, 429, or 5xx response; transient_failure for a network or ordinary transient retry; permanent_or_auth_failure for another non-2xx response; manual_redelivery or configuration_changed for those queue actions. null while an attempt is in flight or once the delivery is terminal. */
2259
+ retry_schedule_reason: "receiver_retry_after" | "transient_failure" | "permanent_or_auth_failure" | "manual_redelivery" | "configuration_changed" | null;
1867
2260
  created_at: string;
1868
2261
  };
1869
2262
  export type WebhookEndpoint = {
@@ -1873,13 +2266,14 @@ export type WebhookEndpoint = {
1873
2266
  url: string;
1874
2267
  event_types: WebhookEventType[];
1875
2268
  status: WebhookStatus;
1876
- verified_at?: string | null;
2269
+ verified_at: string | null;
1877
2270
  verification_token_expires_at: string;
1878
2271
  failure_count: number;
1879
2272
  created_at: string;
1880
2273
  updated_at: string;
1881
2274
  retry_policy: WebhookRetryPolicy;
1882
- /** Returned only on create or rotate-secret. */
2275
+ secret_rotation: WebhookSecretRotation;
2276
+ /** Returned only on create, immediate rotate-secret, staged rotate-secret/prepare, or staged rotate-secret/activate. Never returned by list, get, update, delete, verify, or retire. */
1883
2277
  signing_secret?: string;
1884
2278
  verification?: WebhookVerification;
1885
2279
  };
@@ -1902,6 +2296,12 @@ export type WebhookRetryPolicy = {
1902
2296
  /** Consecutive failed attempts, across all of this endpoint's deliveries, after which the endpoint is disabled and its queued deliveries are dead-lettered. Any successful attempt resets the count. */
1903
2297
  disable_after_consecutive_failures: 8;
1904
2298
  };
2299
+ export type WebhookSecretRotation = {
2300
+ /** idle when no staged rotation exists, pending after prepare, and overlap after activate while both signing secrets are accepted. */
2301
+ status: "idle" | "pending" | "overlap";
2302
+ /** When the previous signing secret stops being emitted and accepted. null outside the overlap phase. */
2303
+ overlap_expires_at: string | null;
2304
+ };
1905
2305
  export type WebhookStatus = "pending_verification" | "active" | "disabled";
1906
2306
  export type WebhookVerification = {
1907
2307
  /** One-time verification token returned only on create or URL change. Pass it to POST /api/v1/webhooks/{id}/verify, which activates the endpoint only when the destination also answers the signed webhook.verification challenge with a 2xx. */
@@ -1915,44 +2315,49 @@ export type WhaleTrade = {
1915
2315
  size_usd: number;
1916
2316
  side: "BUY" | "SELL";
1917
2317
  /** Traded outcome label (e.g. "Yes"/"No"/team name), resolved provider-first from the trade's outcome_index against market_canonical (index 0 -> yes, 1 -> no). Distinct axis from side (BUY/SELL): side is the trade direction, outcome is which leg was traded. null for multi-outcome (outcome_index >= 2) or unsynced markets, and for a Polymarket trade recorded before 2026-04-02T00:00:00Z, whose stored outcome_index is not trusted (a defaulted 0 for about a third of those rows; the side is unknown, not defaulted). */
1918
- outcome?: string | null;
2318
+ outcome: string | null;
1919
2319
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the traded outcome; null when unavailable (e.g. unsynced markets) and for a Polymarket trade recorded before 2026-04-02T00:00:00Z, where the traded side is unknown. */
1920
- token_id?: string | null;
2320
+ token_id: string | null;
1921
2321
  price: number;
1922
- /** Current 0.0–1.0 normalized signal score. This value can change as scoring context changes. */
2322
+ /** Current 0.0–1.0 normalized signal score, computed at request time from the trader's win rate today and the trade's age now. On a historical row it is today's view of the trade, not what a reader saw then; use recorded_signal_score for that. */
1923
2323
  signal_score: number;
1924
- /** 0.0–1.0 signal score written once when the trade row is inserted. Available for new rows after this field launched; legacy rows return null. If a trade is added later, its time-sensitive recorded score reflects that delay. */
2324
+ /** 0.0–1.0 signal score written once when the trade row is inserted, from the trader's statistics at that moment. Populated from 2026-08-03T11:59Z; older rows return null and are never backfilled, because a backfill could only read today's statistics. If a trade is added later, its time-sensitive recorded score reflects that delay. */
1925
2325
  recorded_signal_score: number | null;
1926
2326
  /** Persisted live suspicion score from the scorer. Null when the row has no persisted score. */
1927
2327
  suspicion_score: number | null;
1928
2328
  /** Persisted scorer track. Null when a legacy row has no stored track label. */
1929
- suspicion_track: "whale" | "fresh_conviction" | "sliced_position";
2329
+ suspicion_track: "whale" | "fresh_conviction" | "sliced_position" | null;
1930
2330
  /** This fill's size relative to its market: size_usd divided by the market's volume at the moment the trade was inserted. A $10,000 fill is 0.00005 of a $200M market and 0.125 of an $80,000 one, which size_usd alone cannot distinguish. Absent when the market carried no volume figure and on rows written before 2026-09-16; never 0 as a stand-in. Not capped at 1: a fill larger than the stored trailing volume is real, and that is the most significant case. */
1931
2331
  market_volume_share?: number;
1932
2332
  trader: {
1933
2333
  id: string;
1934
2334
  address: string;
1935
- username?: string | null;
1936
- grade?: string | null;
2335
+ username?: string;
2336
+ /** The trader's grade today, on every row however old. For what the grade was when the trade happened, read grade_at_trade. */
2337
+ grade?: string;
2338
+ /** The grade the trader held when the trade happened, from recorded grade history (recorded from 2026-09-19T23:00Z). Null unless grade_at_trade_status is graded. Never today's grade projected backward. */
2339
+ grade_at_trade: "S" | "A" | "B" | "C" | "D" | "F" | null;
2340
+ /** graded: grade_at_trade holds the recorded grade. ungraded: the trader was recorded without a grade at that moment. unknown: no record covers the moment, which is every trade before 2026-09-19T23:00Z and a trade that fell between a grade change and its confirmation. unknown never means ungraded. */
2341
+ grade_at_trade_status: "graded" | "ungraded" | "unknown";
1937
2342
  };
1938
2343
  market: {
1939
2344
  id: string;
1940
2345
  condition_id: string;
1941
2346
  title: string;
1942
- slug?: string | null;
2347
+ slug?: string;
1943
2348
  /** Provider-backed market_canonical category. */
1944
- category?: string | null;
2349
+ category?: string;
1945
2350
  };
1946
2351
  };
1947
2352
  export type WhaleTradeDetail = WhaleTrade & {
1948
2353
  counterparty_analysis: CounterpartyAnalysis;
1949
2354
  };
1950
2355
  export type WhaleTradeHistoryMeta = {
1951
- /** Unique request ID (req_ prefix). */
2356
+ /** Unique request ID (req_ prefix). The same value as the X-Request-Id response header, the request's usage accounting row and its log lines. */
1952
2357
  request_id: string;
1953
2358
  cached: boolean;
1954
- /** Cache age in seconds, null if not cached. */
1955
- cache_age_s?: number | null;
2359
+ /** Cache age in seconds; the key is absent when the response was not cached. */
2360
+ cache_age_s?: number;
1956
2361
  source: {
1957
2362
  kind: "local_replay";
1958
2363
  table: "whale_alerts";
@@ -1970,6 +2375,7 @@ export type WhaleTradeHistoryMeta = {
1970
2375
  * convenience method.
1971
2376
  */
1972
2377
  export interface OperationData {
2378
+ activateWebhookSecret: WebhookEndpoint;
1973
2379
  batchGetMarketIntel: BatchMarketIntelItem[];
1974
2380
  batchGetTraders: BatchTraderItem[];
1975
2381
  createMcpJsonRpcResponse: {
@@ -1988,6 +2394,13 @@ export interface OperationData {
1988
2394
  user_id: number;
1989
2395
  credential_id: number;
1990
2396
  credential_kind: "api_key" | "oauth_grant";
2397
+ /** The credential is currently valid; revoked, expired or unknown credentials are rejected. */
2398
+ credential_status: "active";
2399
+ entitlement: {
2400
+ paid_data_access: "active" | "lapsed";
2401
+ /** When paid data access is lapsed, the caller should renew the subscription; otherwise null. */
2402
+ recovery_action: "renew_subscription" | null;
2403
+ };
1991
2404
  /** Approved OAuth scopes; null for full developer-key access. */
1992
2405
  scopes: string[] | null;
1993
2406
  };
@@ -1999,6 +2412,8 @@ export interface OperationData {
1999
2412
  db?: boolean;
2000
2413
  cache?: boolean;
2001
2414
  subsystems?: {
2415
+ /** Whether the webhook outbox schema validated on this probe. false lowers status to degraded. true during a maintenance window, when nothing is probed. */
2416
+ webhook_compatibility: boolean;
2002
2417
  /** Public-safe aggregate status for expected background job successful-completion heartbeats. Does not expose Redis keys, job names, raw errors, provider payloads, wallet addresses, or condition IDs. */
2003
2418
  background_jobs: {
2004
2419
  status: "ok" | "degraded" | "down" | "not_checked";
@@ -2017,17 +2432,20 @@ export interface OperationData {
2017
2432
  getInsiderRadarFlag: RadarFlag;
2018
2433
  getMarketCandles: MarketCandles;
2019
2434
  getMarketContextMarkdown: string;
2435
+ getMarketHolders: MarketHolder[];
2020
2436
  getMarketIntel: MarketIntel;
2021
2437
  getMarketSnapshot: MarketSnapshot;
2022
2438
  getMonthlyReportSnapshot: ReportSnapshot;
2023
2439
  getPickOfTheDay: PickOfTheDay;
2024
2440
  getPickOfTheDayArchive: PickOfTheDayArchive;
2441
+ getPickOfTheDayLedger: PickOfTheDayLedger;
2025
2442
  getPlatforms: Platforms;
2026
2443
  getPositionTimeline: PositionTimelineEvent[];
2027
2444
  getPositionTimelineById: PositionTimelineEvent[];
2028
2445
  getReports: ReportSnapshot;
2029
2446
  getStream: string;
2030
2447
  getTrader: Trader;
2448
+ getTraderCategoryRecords: TraderCategoryRecords;
2031
2449
  getTraderContext: TraderContext;
2032
2450
  getTraderContextMarkdown: string;
2033
2451
  getTraderExportSnapshot: TraderExportSnapshot;
@@ -2035,10 +2453,10 @@ export interface OperationData {
2035
2453
  job_id: number;
2036
2454
  status: "queued" | "running" | "ready" | "failed";
2037
2455
  format: "json" | "ndjson" | "csv";
2038
- total_trades?: number | null;
2039
- processed_trades?: number | null;
2040
- file_size?: number | null;
2041
- error?: string | null;
2456
+ total_trades: number | null;
2457
+ processed_trades: number | null;
2458
+ file_size: number | null;
2459
+ error: string | null;
2042
2460
  };
2043
2461
  getTraderPnl: TraderPnl;
2044
2462
  getUsage: {
@@ -2057,6 +2475,24 @@ export interface OperationData {
2057
2475
  reset_at: number;
2058
2476
  window_seconds: number;
2059
2477
  };
2478
+ /** The monthly request quota (#16111): where the account stands against the requests Pro includes per UTC calendar month. Reading it here spends nothing. null only when the month's count could not be read for this response. */
2479
+ monthly_quota: {
2480
+ /** Admitted requests so far this UTC calendar month. */
2481
+ used: number;
2482
+ /** Requests Pro includes per UTC calendar month. */
2483
+ limit: number;
2484
+ remaining: number;
2485
+ /** Unix seconds: the first instant of the next UTC calendar month. */
2486
+ reset_at: number;
2487
+ /** Unix seconds: from when request limit + 1 is refused for an account the quota binds. */
2488
+ enforced_from: number;
2489
+ /** Whether requests over this account's ceiling are refused right now: false before enforced_from and for an admin account. */
2490
+ binding: boolean;
2491
+ /** Pay as you go is on: requests over the quota keep answering and bill on a monthly invoice, up to ceiling. */
2492
+ pay_as_you_go: boolean;
2493
+ /** The most requests this account is admitted in a UTC calendar month once enforcement has begun: limit, or 1,000,000 with pay as you go on. null for an admin account, which no number stops. Additive since 2026-09-22. */
2494
+ ceiling: number | null;
2495
+ } | null;
2060
2496
  };
2061
2497
  getWebhook: WebhookEndpoint;
2062
2498
  getWeeklyReportSnapshot: ReportSnapshot;
@@ -2077,8 +2513,10 @@ export interface OperationData {
2077
2513
  listWhaleTradeCounterpartyMakers: CounterpartyMakerPage;
2078
2514
  listWhaleTradeHistory: WhaleTrade[];
2079
2515
  listWhaleTrades: WhaleTrade[];
2080
- openMcpEventStream: string;
2516
+ prepareWebhookSecret: WebhookEndpoint;
2081
2517
  redeliverWebhookDelivery: WebhookDelivery;
2518
+ registerAgent: AgentRegistration;
2519
+ retireWebhookSecret: WebhookEndpoint;
2082
2520
  rotateWebhookSecret: WebhookEndpoint;
2083
2521
  searchContent: ContentSearchResult[];
2084
2522
  searchMarkets: MarketSearchResult[];
@@ -2086,22 +2524,20 @@ export interface OperationData {
2086
2524
  job_id: number;
2087
2525
  status: "queued" | "running" | "ready" | "failed";
2088
2526
  format: "json" | "ndjson" | "csv";
2089
- total_trades?: number | null;
2090
- processed_trades?: number | null;
2091
- file_size?: number | null;
2092
- error?: string | null;
2527
+ total_trades: number | null;
2528
+ processed_trades: number | null;
2529
+ file_size: number | null;
2530
+ error: string | null;
2093
2531
  };
2094
2532
  updateWebhook: WebhookEndpoint;
2095
2533
  verifyWebhook: WebhookEndpoint;
2096
2534
  }
2097
2535
  /** Each operation's documented query parameters. */
2098
2536
  export interface OperationQuery {
2537
+ activateWebhookSecret: Record<string, never>;
2099
2538
  batchGetMarketIntel: Record<string, never>;
2100
2539
  batchGetTraders: Record<string, never>;
2101
- createMcpJsonRpcResponse: {
2102
- /** Legacy API-key query parameter for exact /api/v1/mcp only. Every other protected V1 route rejects it. Prefer Authorization: Bearer <token> or the stdio package because URL secrets are easier to leak through logs and history. The retirement date is unknown until external URL-only client compatibility is checked. */
2103
- token?: string;
2104
- };
2540
+ createMcpJsonRpcResponse: Record<string, never>;
2105
2541
  createWebhook: Record<string, never>;
2106
2542
  deleteWebhook: Record<string, never>;
2107
2543
  exploreMarkets: {
@@ -2127,22 +2563,42 @@ export interface OperationQuery {
2127
2563
  date: string;
2128
2564
  };
2129
2565
  getEventReplaySince: {
2130
- /** Opaque event replay cursor returned as next_cursor by a prior response. The cursor maps to whale_alerts.id and is valid across backend replicas. Omit to fetch the latest durable public suffix. */
2566
+ /** Opaque event replay cursor returned as next_cursor by a prior response. The cursor maps to the global (whale_alerts.inserted_xid, whale_alerts.id) commit-order position, is valid across backend replicas, and is bound to the filter set the walk ran with (trader, condition_id, min_grade, min_size): presenting it under different filters answers 400 bad_request with error.reason cursor_expired, and the walk restarts without a cursor. Cursors issued before 2026-09-22 (id-only) stay accepted and are bound to no filters. Omit to fetch the latest durable public suffix. */
2131
2567
  cursor?: string;
2132
2568
  /** Maximum durable public whale-trade events to return. */
2133
2569
  limit?: number;
2570
+ /** Only this wallet's trades: a wallet address, trd_-prefixed trader id or username resolved against the traders table. Bound to the cursor: a cursor issued under other filters answers 400 with error.reason cursor_expired. An unknown trader matches nothing and the walk still advances. */
2571
+ trader?: string;
2572
+ /** Only trades on this market: the raw provider condition_id or its mkt_-prefixed id. Bound to the cursor. */
2573
+ condition_id?: string;
2574
+ /** Only trades by wallets at this grade or better (S best), read from the wallet's newest ranking at request time; a wallet with no grade never passes. Bound to the cursor. */
2575
+ min_grade?: "S" | "A" | "B" | "C" | "D" | "F";
2576
+ /** Only trades of at least this size in USD (compared in cents). Bound to the cursor. */
2577
+ min_size?: number;
2578
+ /** Repeatable. trade adds the public trade read to every event (the object GET /api/v1/whale-trades/{id} returns for it), from one query per page, so a page of 100 events needs no per-event detail request. Not bound to the cursor: switch it on or off mid-walk. */
2579
+ expand?: "trade"[];
2134
2580
  };
2135
2581
  getHealth: Record<string, never>;
2136
2582
  getInsiderRadarFlag: Record<string, never>;
2137
2583
  getMarketCandles: {
2138
2584
  /** Bucketing granularity. 1d aggregates by UTC calendar day, 1w by ISO week (Monday 00:00 UTC start). Defaults to 1d. */
2139
2585
  resolution?: "1d" | "1w";
2140
- /** Exclusive lower bound as a unix timestamp in seconds; points at or before this timestamp are omitted (the underlying daily snapshot read filters bucket_start > from). Note: for resolution=1w a surviving mid-week point can yield a weekly candle whose t (Monday 00:00 UTC) precedes from. */
2586
+ /** Exclusive lower bound as a URL-decoded unix timestamp in seconds; points at or before this timestamp are omitted (the underlying daily snapshot read filters bucket_start > from). If to is also present, from must be less than or equal to to. Note: for resolution=1w a surviving mid-week point can yield a weekly candle whose t (Monday 00:00 UTC) precedes from. */
2141
2587
  from?: number;
2142
- /** Inclusive upper bound as a unix timestamp in seconds; points after this timestamp are omitted. */
2588
+ /** Inclusive upper bound as a URL-decoded unix timestamp in seconds; points after this timestamp are omitted. If from is also present, from must be less than or equal to to. */
2143
2589
  to?: number;
2144
2590
  };
2145
2591
  getMarketContextMarkdown: Record<string, never>;
2592
+ getMarketHolders: {
2593
+ /** Keep holders netting one side. `all` (default) lists both. */
2594
+ outcome?: "yes" | "no" | "all";
2595
+ /** Narrow within the graded cohort: `S` keeps S, `A` keeps S and A, `B` (default) keeps S, A and B. `C`, `D` and `F` are rejected with 400: the route lists the S/A/B cohort only. The cohort is the wallet's current grade (`traders.latest_grade`), so no value here reaches a C, D, F or ungraded holder; those are counted only in `scan.wallet_count`. `min_grade=D` on GET /api/v1/positions does return C and D, which is one of the three reasons the two routes' counts differ for the same market. */
2596
+ min_grade?: "S" | "A" | "B";
2597
+ /** Maximum holders per page. */
2598
+ limit?: number;
2599
+ /** Opaque pagination cursor from the previous response's next_cursor. It encodes a page of one shared roster, so it stays valid across the roster's refresh, but a page read after a refresh can repeat or skip a holder. */
2600
+ cursor?: string;
2601
+ };
2146
2602
  getMarketIntel: {
2147
2603
  /** Lookback window for whale flow aggregation. */
2148
2604
  timeframe?: "1h" | "4h" | "24h" | "7d";
@@ -2159,6 +2615,7 @@ export interface OperationQuery {
2159
2615
  };
2160
2616
  getPickOfTheDay: Record<string, never>;
2161
2617
  getPickOfTheDayArchive: Record<string, never>;
2618
+ getPickOfTheDayLedger: Record<string, never>;
2162
2619
  getPlatforms: Record<string, never>;
2163
2620
  getPositionTimeline: {
2164
2621
  /** Market condition_id. One timeline per (trader, market). */
@@ -2179,7 +2636,7 @@ export interface OperationQuery {
2179
2636
  getReports: {
2180
2637
  /** Report granularity selector. */
2181
2638
  granularity: "daily" | "weekly" | "monthly";
2182
- /** Period token for the granularity. daily: UTC date YYYY-MM-DD. weekly: ISO week YYYY-WW, or a from,to YYYY-MM-DD pair. monthly: UTC month YYYY-MM. */
2639
+ /** Period token for the granularity. daily: UTC date YYYY-MM-DD. weekly: ISO week YYYY-WW for a durable canonical snapshot, or a from,to YYYY-MM-DD pair for an exact ephemeral range limited to 31 inclusive UTC days. A wider explicit range returns 400 invalid_query. monthly: UTC month YYYY-MM. */
2183
2640
  period: string;
2184
2641
  };
2185
2642
  getStream: {
@@ -2200,6 +2657,10 @@ export interface OperationQuery {
2200
2657
  /** Include heavy fields and trust metadata. Repeatable: strategy, categories, quant_metrics, trust. */
2201
2658
  expand?: ("strategy" | "categories" | "quant_metrics" | "trust")[];
2202
2659
  };
2660
+ getTraderCategoryRecords: {
2661
+ /** Filter to one canonical category, matched through the same rollup every other category surface uses: soccer, EPL and champions league all reach Soccer, every esports label folds into Esports, and football is AMERICAN football and reaches Football. A filter that reaches Esports returns the Esports record with all of its games; a game is not a filter of its own, so ask for esports and read games. A value that matches no record answers 200 with an empty records array, never 404. */
2662
+ category?: string;
2663
+ };
2203
2664
  getTraderContext: Record<string, never>;
2204
2665
  getTraderContextMarkdown: Record<string, never>;
2205
2666
  getTraderExportSnapshot: Record<string, never>;
@@ -2211,11 +2672,11 @@ export interface OperationQuery {
2211
2672
  getUsage: Record<string, never>;
2212
2673
  getWebhook: Record<string, never>;
2213
2674
  getWeeklyReportSnapshot: {
2214
- /** UTC source-range start in YYYY-MM-DD format; required with to. */
2675
+ /** UTC source-range start in YYYY-MM-DD format; required with to. Together with to, selects an exact ephemeral range of at most 31 inclusive UTC days. */
2215
2676
  from?: string;
2216
- /** UTC source-range end in YYYY-MM-DD format; required with from. */
2677
+ /** UTC source-range end in YYYY-MM-DD format; required with from. Together with from, selects an exact ephemeral range of at most 31 inclusive UTC days. */
2217
2678
  to?: string;
2218
- /** ISO week selector in YYYY-WW format; alternative to from/to. */
2679
+ /** ISO week selector in YYYY-WW format; alternative to from/to. Selects a durable canonical snapshot. */
2219
2680
  week?: string;
2220
2681
  };
2221
2682
  getWhaleTrade: Record<string, never>;
@@ -2228,13 +2689,15 @@ export interface OperationQuery {
2228
2689
  min_suspicion?: number;
2229
2690
  /** Compatible filter. flag selects live threshold crossings. watch returns no rows because no live watch policy exists. */
2230
2691
  severity?: "flag" | "watch";
2692
+ /** Pagination mode. live (default) keeps the 120-second response cache; stable pins the walk to one published scoring generation and binds the cursor to the limit and filters. */
2693
+ mode?: "live" | "stable";
2231
2694
  };
2232
2695
  listLargePositions: {
2233
2696
  /** Maximum number of large positions to return. */
2234
2697
  limit?: number;
2235
2698
  /** Opaque pagination cursor from a previous response. */
2236
2699
  cursor?: string;
2237
- /** Minimum position value in USD. */
2700
+ /** Minimum position value in USD. Raises the feed's own floor of 50,000 USD; a smaller value does not lower it. */
2238
2701
  min_size?: number;
2239
2702
  /** One RFC 4180 CSV record of exact current provider-backed market_canonical.category values. Legacy unquoted lists such as NBA,WNBA remain valid; values containing commas, quotes, or newlines are CSV-quoted. Matching is case-insensitive. Malformed quoted input fails closed as one unknown exact category. */
2240
2703
  category?: string;
@@ -2258,10 +2721,16 @@ export interface OperationQuery {
2258
2721
  limit?: number;
2259
2722
  /** Pagination cursor from previous response's next_cursor. */
2260
2723
  cursor?: string;
2261
- /** Minimum current position value in USD. */
2724
+ /** Minimum current position value in USD. Defaults to 100 when omitted, or to 0 when wallet is present; send 0 to include every reconciled position. */
2262
2725
  min_size?: number;
2263
2726
  /** Exact match against provider-backed market_canonical.category. */
2264
2727
  category?: string;
2728
+ /** Scope to one market. Accepts the raw provider condition_id or the mkt_-prefixed market id emitted by V1 responses. Combine with min_size=0 for every reconciled position in that market; an unknown id returns []. */
2729
+ condition_id?: string;
2730
+ /** Scope to one wallet or a book of wallets (repeatable, up to 25 per request; comma-separated values inside one occurrence also work). Each value is a wallet address, a known username, or a trd_-prefixed trader id, resolved like /api/v1/trader/{address}. The response keeps the board's order and cursor, so pages of a book interleave wallets by current_value_usd. An address this API has never tracked returns its mirror rows or an empty list; a username or trader id that resolves to nothing is a 404 naming wallet; more than 25 values is a 400. min_size defaults to 0 when wallet is present. */
2731
+ wallet?: string[];
2732
+ /** Backward-compatible bracket alias for wallet. Repeatable; same values and limits. */
2733
+ "wallet[]"?: string[];
2265
2734
  /** Minimum trader grade allowlist. `A` matches S and A; `B` matches S, A, B; etc. */
2266
2735
  min_grade?: "S" | "A" | "B" | "C" | "D" | "F";
2267
2736
  /** Filter by the binary outcome side. `yes` maps to outcome_index=0, `no` to outcome_index=1. */
@@ -2272,7 +2741,7 @@ export interface OperationQuery {
2272
2741
  timeframe?: "1h" | "4h" | "24h" | "7d";
2273
2742
  /** Page size. */
2274
2743
  limit?: number;
2275
- /** Opaque cursor from previous response's next_cursor. Encodes the first-page as_of timestamp plus the last row's absolute net flow and condition_id. */
2744
+ /** Opaque cursor from previous response's next_cursor. Encodes the first-page as_of timestamp, normalized effective filters, ranking and aggregate collection revisions, plus the last row's absolute net flow and condition_id. A changed filter or collection returns cursor_expired; request the first page again. */
2276
2745
  cursor?: string;
2277
2746
  /** Filter by market category (case-insensitive). A canonical bucket name (e.g. Basketball) matches every provider member that folds into it (NBA, WNBA, NCAAB); a raw provider value also resolves to its bucket. */
2278
2747
  category?: string;
@@ -2288,7 +2757,7 @@ export interface OperationQuery {
2288
2757
  timeframe?: "1h" | "4h" | "24h" | "7d";
2289
2758
  /** Page size. */
2290
2759
  limit?: number;
2291
- /** Opaque cursor from previous response's next_cursor. Encodes the first-page as_of timestamp plus the last row's absolute net flow and condition_id. */
2760
+ /** Opaque cursor from previous response's next_cursor. Encodes the first-page as_of timestamp, normalized effective filters, ranking and aggregate collection revisions, plus the last row's absolute net flow and condition_id. A changed filter or collection returns cursor_expired; request the first page again. */
2292
2761
  cursor?: string;
2293
2762
  /** Filter by market category (case-insensitive). A canonical bucket name (e.g. Basketball) matches every provider member that folds into it (NBA, WNBA, NCAAB); a raw provider value also resolves to its bucket. */
2294
2763
  category?: string;
@@ -2324,7 +2793,7 @@ export interface OperationQuery {
2324
2793
  listTrendingWallets: {
2325
2794
  /** Polymarket's weekly leaderboard caps the ranked set at 50 wallets; requests above 50 still return at most 50. */
2326
2795
  limit?: number;
2327
- /** Opaque pagination cursor from a previous response. */
2796
+ /** Opaque pagination cursor from a previous response, bound to its effective limit, window and ranked-board generation. A changed board or request scope returns error.reason=cursor_expired; legacy page-only cursors must restart from page one. */
2328
2797
  cursor?: string;
2329
2798
  /** Trailing window. */
2330
2799
  window?: "7d" | "30d";
@@ -2332,7 +2801,7 @@ export interface OperationQuery {
2332
2801
  listWebhookDeliveries: {
2333
2802
  /** Opaque pagination cursor returned as next_cursor by a prior response. Omit to fetch the newest page. */
2334
2803
  cursor?: string;
2335
- /** Maximum delivery rows to return per page. */
2804
+ /** Maximum delivery rows to return per page. Out-of-range values are clamped to 1..100. */
2336
2805
  limit?: number;
2337
2806
  };
2338
2807
  listWebhookEvents: Record<string, never>;
@@ -2358,15 +2827,15 @@ export interface OperationQuery {
2358
2827
  limit?: number;
2359
2828
  /** Pagination cursor from previous response's next_cursor. Prefix: wth_. URL-encode when replaying as a query parameter. */
2360
2829
  cursor?: string;
2361
- /** Minimum trade size in USD. */
2830
+ /** Minimum trade size in USD. The capture floor was 3,000 USD before 2026-07-06 and 10,000 USD from then (1,000 USD in earnings markets), so 10000 gives one size rule across the whole archive. */
2362
2831
  min_size?: number;
2363
2832
  /** Exact raw provider condition_id. Unknown markets return an empty list. */
2364
2833
  condition_id?: string;
2365
- /** Trader wallet address, timestamp-suffixed wallet alias, or username resolved against the traders table. Unknown traders return an empty list. */
2834
+ /** Trader wallet address, timestamp-suffixed wallet alias, username, or trd_-prefixed trader ID, resolved against the traders table. Unknown traders return an empty list. */
2366
2835
  trader?: string;
2367
2836
  /** Filter by market category (case-insensitive). A canonical bucket name (e.g. Basketball) matches every provider member that folds into it (NBA, WNBA, NCAAB); a raw provider value also resolves to its bucket. */
2368
2837
  category?: string;
2369
- /** Minimum trader grade. */
2838
+ /** Minimum trader grade as of today (trader.grade), not at trade time. On a historical window it selects wallets by a grade they may have earned after the trade; for a point-in-time rule filter on trader.grade_at_trade instead. A means S or A, B means S, A or B. */
2370
2839
  min_grade?: "S" | "A" | "B" | "C" | "D" | "F";
2371
2840
  /** When true, return only rows with persisted suspicion_score >= 60. The filter is applied before SQL-backed limit + 1 pagination. */
2372
2841
  suspicious_only?: boolean;
@@ -2386,16 +2855,15 @@ export interface OperationQuery {
2386
2855
  min_size?: number;
2387
2856
  /** Filter by market category (case-insensitive). A canonical bucket name (e.g. Basketball) matches every provider member that folds into it (NBA, WNBA, NCAAB); a raw provider value also resolves to its bucket. */
2388
2857
  category?: string;
2389
- /** Minimum trader grade. */
2858
+ /** Minimum trader grade as of today (trader.grade). A means S or A, B means S, A or B. */
2390
2859
  min_grade?: "S" | "A" | "B" | "C" | "D" | "F";
2391
2860
  /** When true, return only rows with persisted suspicion_score >= 60. The filter is applied before SQL-backed limit + 1 pagination. */
2392
2861
  suspicious_only?: boolean;
2393
2862
  };
2394
- openMcpEventStream: {
2395
- /** Legacy API-key query parameter for exact /api/v1/mcp only. Every other protected V1 route rejects it. Same contract as POST. */
2396
- token?: string;
2397
- };
2863
+ prepareWebhookSecret: Record<string, never>;
2398
2864
  redeliverWebhookDelivery: Record<string, never>;
2865
+ registerAgent: Record<string, never>;
2866
+ retireWebhookSecret: Record<string, never>;
2399
2867
  rotateWebhookSecret: Record<string, never>;
2400
2868
  searchContent: {
2401
2869
  /** Search query. Must be 1-256 characters before whitespace trimming and non-empty after trimming. */
@@ -2422,4 +2890,642 @@ export interface OperationQuery {
2422
2890
  updateWebhook: Record<string, never>;
2423
2891
  verifyWebhook: Record<string, never>;
2424
2892
  }
2893
+ /** Each operation's path parameters; `Record<string, never>` when the path has none. */
2894
+ export interface OperationPath {
2895
+ activateWebhookSecret: {
2896
+ /** Webhook endpoint id owned by the authenticated API key user. */
2897
+ id: number;
2898
+ };
2899
+ batchGetMarketIntel: Record<string, never>;
2900
+ batchGetTraders: Record<string, never>;
2901
+ createMcpJsonRpcResponse: Record<string, never>;
2902
+ createWebhook: Record<string, never>;
2903
+ deleteWebhook: {
2904
+ /** Webhook endpoint id owned by the authenticated API key user. */
2905
+ id: number;
2906
+ };
2907
+ exploreMarkets: Record<string, never>;
2908
+ getAccountIdentity: Record<string, never>;
2909
+ getApiDiscovery: Record<string, never>;
2910
+ getDailyReportSnapshot: Record<string, never>;
2911
+ getEventReplaySince: Record<string, never>;
2912
+ getHealth: Record<string, never>;
2913
+ getInsiderRadarFlag: {
2914
+ /** Raw whale_alerts.id or rf_-prefixed radar flag id. */
2915
+ id: string;
2916
+ };
2917
+ getMarketCandles: {
2918
+ /** Market condition ID. Accepts the raw provider-backed condition_id returned by /api/v1/markets/search or /api/v1/markets/explore, or the mkt_-prefixed market.id emitted by V1 responses. */
2919
+ condition_id: string;
2920
+ };
2921
+ getMarketContextMarkdown: {
2922
+ /** Market condition ID. Accepts the raw provider-backed condition_id returned by /api/v1/markets/search or /api/v1/markets/explore, or the mkt_-prefixed market.id emitted by V1 responses. */
2923
+ condition_id: string;
2924
+ };
2925
+ getMarketHolders: {
2926
+ /** Market condition ID. Accepts the raw provider-backed condition_id returned by /api/v1/markets/search or the mkt_-prefixed market.id emitted by V1 responses. */
2927
+ condition_id: string;
2928
+ };
2929
+ getMarketIntel: {
2930
+ /** Market condition ID. Accepts the raw provider-backed condition_id returned by /api/v1/markets/search or the mkt_-prefixed market.id emitted by V1 responses. */
2931
+ condition_id: string;
2932
+ };
2933
+ getMarketSnapshot: {
2934
+ /** Market condition ID. Accepts the raw provider-backed condition_id returned by /api/v1/markets/search or /api/v1/markets/explore, or the mkt_-prefixed market.id emitted by V1 responses. */
2935
+ condition_id: string;
2936
+ };
2937
+ getMonthlyReportSnapshot: Record<string, never>;
2938
+ getPickOfTheDay: Record<string, never>;
2939
+ getPickOfTheDayArchive: Record<string, never>;
2940
+ getPickOfTheDayLedger: Record<string, never>;
2941
+ getPlatforms: Record<string, never>;
2942
+ getPositionTimeline: {
2943
+ /** Trader identity: 0x... wallet address, username, trd_-prefixed trader id, bare integer traders.id, or @username. Resolved with precedence @username -> wallet -> trd_ -> integer -> username (a leading @ forces a username lookup, for all-digit usernames); wallet matching is case-insensitive. */
2944
+ address: string;
2945
+ };
2946
+ getPositionTimelineById: {
2947
+ /** Trader identity: 0x... wallet address, username, trd_-prefixed trader id, bare integer traders.id, or @username. Resolved with precedence @username -> wallet -> trd_ -> integer -> username (a leading @ forces a username lookup, for all-digit usernames). Unknown identities return 404. */
2948
+ trader: string;
2949
+ };
2950
+ getReports: Record<string, never>;
2951
+ getStream: Record<string, never>;
2952
+ getTrader: {
2953
+ /** Ethereum wallet address (0x...), known trader username, or trd_-prefixed trader ID emitted by this API. */
2954
+ address: string;
2955
+ };
2956
+ getTraderCategoryRecords: {
2957
+ /** Wallet address (0x...), username, or trd_-prefixed trader id. */
2958
+ address: string;
2959
+ };
2960
+ getTraderContext: {
2961
+ /** Ethereum wallet address (0x...), known trader username, or trd_-prefixed trader ID emitted by this API. */
2962
+ address: string;
2963
+ };
2964
+ getTraderContextMarkdown: {
2965
+ /** Ethereum wallet address (0x...), known trader username, or trd_-prefixed trader ID emitted by this API. */
2966
+ address: string;
2967
+ };
2968
+ getTraderExportSnapshot: {
2969
+ /** Trader wallet address (0x...), known trader username-style lookup, or trd_-prefixed trader ID emitted by this API. Bare integer database IDs are not accepted. */
2970
+ address: string;
2971
+ };
2972
+ getTraderExportStatus: {
2973
+ /** Trader wallet address (0x...), known trader username-style lookup, or trd_-prefixed trader ID emitted by this API. */
2974
+ address: string;
2975
+ };
2976
+ getTraderPnl: {
2977
+ /** Wallet address (0x...), username, or trd_-prefixed trader id. */
2978
+ address: string;
2979
+ };
2980
+ getUsage: Record<string, never>;
2981
+ getWebhook: {
2982
+ /** Webhook endpoint id owned by the authenticated API key user. */
2983
+ id: number;
2984
+ };
2985
+ getWeeklyReportSnapshot: Record<string, never>;
2986
+ getWhaleTrade: {
2987
+ /** Raw whale_alerts.id or wt_-prefixed whale trade id. */
2988
+ id: string;
2989
+ };
2990
+ listInsiderRadar: Record<string, never>;
2991
+ listLargePositions: Record<string, never>;
2992
+ listLeaderboard: Record<string, never>;
2993
+ listPositions: Record<string, never>;
2994
+ listSharpMoneyFlows: Record<string, never>;
2995
+ listSmartMoneyFlows: Record<string, never>;
2996
+ listSportsEdgeObservations: Record<string, never>;
2997
+ listSportsEdgeSignals: Record<string, never>;
2998
+ listTrendingWallets: Record<string, never>;
2999
+ listWebhookDeliveries: {
3000
+ /** Webhook endpoint id owned by the authenticated API key user. */
3001
+ id: number;
3002
+ };
3003
+ listWebhookEvents: Record<string, never>;
3004
+ listWebhooks: Record<string, never>;
3005
+ listWhaleTradeCounterpartyExecutions: {
3006
+ /** Whale trade ID. Accepts wt_-prefixed or raw whale_alerts.id. */
3007
+ id: string;
3008
+ };
3009
+ listWhaleTradeCounterpartyMakers: {
3010
+ /** Whale trade ID. Accepts wt_-prefixed or raw whale_alerts.id. */
3011
+ id: string;
3012
+ /** Counterparty execution ID from the parent response. */
3013
+ execution_id: string;
3014
+ };
3015
+ listWhaleTradeHistory: Record<string, never>;
3016
+ listWhaleTrades: Record<string, never>;
3017
+ prepareWebhookSecret: {
3018
+ /** Webhook endpoint id owned by the authenticated API key user. */
3019
+ id: number;
3020
+ };
3021
+ redeliverWebhookDelivery: {
3022
+ /** Webhook endpoint id owned by the authenticated API key user. */
3023
+ id: number;
3024
+ /** Delivery id from GET /api/v1/webhooks/{id}/deliveries. It must belong to the webhook endpoint named by id. */
3025
+ delivery_id: number;
3026
+ };
3027
+ registerAgent: Record<string, never>;
3028
+ retireWebhookSecret: {
3029
+ /** Webhook endpoint id owned by the authenticated API key user. */
3030
+ id: number;
3031
+ };
3032
+ rotateWebhookSecret: {
3033
+ /** Webhook endpoint id owned by the authenticated API key user. */
3034
+ id: number;
3035
+ };
3036
+ searchContent: Record<string, never>;
3037
+ searchMarkets: Record<string, never>;
3038
+ submitTraderExport: {
3039
+ /** Trader wallet address (0x...), known trader username-style lookup, or trd_-prefixed trader ID emitted by this API. */
3040
+ address: string;
3041
+ };
3042
+ updateWebhook: {
3043
+ /** Webhook endpoint id owned by the authenticated API key user. */
3044
+ id: number;
3045
+ };
3046
+ verifyWebhook: {
3047
+ /** Webhook endpoint id owned by the authenticated API key user. */
3048
+ id: number;
3049
+ };
3050
+ }
3051
+ /** Each operation's JSON request body; `never` when it takes none. */
3052
+ export interface OperationBody {
3053
+ activateWebhookSecret: never;
3054
+ batchGetMarketIntel: {
3055
+ /** Market condition IDs to resolve in input order. */
3056
+ condition_ids: string[];
3057
+ /** Lookback window used for flow and trade-count context. */
3058
+ timeframe?: "1h" | "4h" | "24h" | "7d";
3059
+ };
3060
+ batchGetTraders: {
3061
+ /** Trader identities to resolve in input order. */
3062
+ traders: string[];
3063
+ /** Shared expand flags applied to every trader item. */
3064
+ expand?: ("strategy" | "categories" | "quant_metrics" | "trust")[];
3065
+ };
3066
+ createMcpJsonRpcResponse: {
3067
+ /** JSON-RPC protocol version; this server accepts 2.0. */
3068
+ jsonrpc: "2.0";
3069
+ /** Request identifier echoed exactly in one JSON-RPC response; supported notifications omit it and receive an empty HTTP 202. */
3070
+ id?: string | number | null;
3071
+ /** MCP method to invoke. */
3072
+ method: "initialize" | "notifications/initialized" | "notifications/cancelled" | "ping" | "tools/list" | "tools/call";
3073
+ /** Method-specific MCP parameters. */
3074
+ params?: Record<string, unknown>;
3075
+ };
3076
+ createWebhook: CreateWebhookRequest;
3077
+ deleteWebhook: never;
3078
+ exploreMarkets: never;
3079
+ getAccountIdentity: never;
3080
+ getApiDiscovery: never;
3081
+ getDailyReportSnapshot: never;
3082
+ getEventReplaySince: never;
3083
+ getHealth: never;
3084
+ getInsiderRadarFlag: never;
3085
+ getMarketCandles: never;
3086
+ getMarketContextMarkdown: never;
3087
+ getMarketHolders: never;
3088
+ getMarketIntel: never;
3089
+ getMarketSnapshot: never;
3090
+ getMonthlyReportSnapshot: never;
3091
+ getPickOfTheDay: never;
3092
+ getPickOfTheDayArchive: never;
3093
+ getPickOfTheDayLedger: never;
3094
+ getPlatforms: never;
3095
+ getPositionTimeline: never;
3096
+ getPositionTimelineById: never;
3097
+ getReports: never;
3098
+ getStream: never;
3099
+ getTrader: never;
3100
+ getTraderCategoryRecords: never;
3101
+ getTraderContext: never;
3102
+ getTraderContextMarkdown: never;
3103
+ getTraderExportSnapshot: never;
3104
+ getTraderExportStatus: never;
3105
+ getTraderPnl: never;
3106
+ getUsage: never;
3107
+ getWebhook: never;
3108
+ getWeeklyReportSnapshot: never;
3109
+ getWhaleTrade: never;
3110
+ listInsiderRadar: never;
3111
+ listLargePositions: never;
3112
+ listLeaderboard: never;
3113
+ listPositions: never;
3114
+ listSharpMoneyFlows: never;
3115
+ listSmartMoneyFlows: never;
3116
+ listSportsEdgeObservations: never;
3117
+ listSportsEdgeSignals: never;
3118
+ listTrendingWallets: never;
3119
+ listWebhookDeliveries: never;
3120
+ listWebhookEvents: never;
3121
+ listWebhooks: never;
3122
+ listWhaleTradeCounterpartyExecutions: never;
3123
+ listWhaleTradeCounterpartyMakers: never;
3124
+ listWhaleTradeHistory: never;
3125
+ listWhaleTrades: never;
3126
+ prepareWebhookSecret: never;
3127
+ redeliverWebhookDelivery: never;
3128
+ registerAgent: never;
3129
+ retireWebhookSecret: never;
3130
+ rotateWebhookSecret: never;
3131
+ searchContent: never;
3132
+ searchMarkets: never;
3133
+ submitTraderExport: never;
3134
+ updateWebhook: UpdateWebhookRequest;
3135
+ verifyWebhook: VerifyWebhookRequest;
3136
+ }
3137
+ /**
3138
+ * The whole 200 body of each operation: the envelope with its own `object`
3139
+ * literal, `meta` type and top-level fields, `data` as `OperationData[id]`;
3140
+ * `string` for a text body. What `ApiClient.call(id)` resolves to.
3141
+ */
3142
+ export interface OperationResponse {
3143
+ activateWebhookSecret: {
3144
+ object: "webhook";
3145
+ data: OperationData["activateWebhookSecret"];
3146
+ meta: ResponseMeta;
3147
+ };
3148
+ batchGetMarketIntel: {
3149
+ object: "market_intel_batch";
3150
+ data: OperationData["batchGetMarketIntel"];
3151
+ meta: BatchResponseMeta;
3152
+ };
3153
+ batchGetTraders: {
3154
+ object: "trader_batch";
3155
+ data: OperationData["batchGetTraders"];
3156
+ meta: BatchResponseMeta;
3157
+ };
3158
+ createMcpJsonRpcResponse: {
3159
+ jsonrpc: "2.0";
3160
+ id: string | number | null;
3161
+ result?: Record<string, unknown>;
3162
+ error?: {
3163
+ code: number;
3164
+ message: string;
3165
+ };
3166
+ };
3167
+ createWebhook: {
3168
+ object: "webhook";
3169
+ data: OperationData["createWebhook"];
3170
+ meta: ResponseMeta;
3171
+ };
3172
+ deleteWebhook: {
3173
+ object: "webhook";
3174
+ data: OperationData["deleteWebhook"];
3175
+ meta: ResponseMeta;
3176
+ };
3177
+ exploreMarkets: {
3178
+ object: "list";
3179
+ data: OperationData["exploreMarkets"];
3180
+ has_more: boolean;
3181
+ next_cursor?: string;
3182
+ /** Total matching visible entries after grouping. Present on the first page and omitted on cursor pages. */
3183
+ total?: number;
3184
+ facets: ExploreFacets;
3185
+ meta: ResponseMeta;
3186
+ /** When this response body was computed. Present whenever the body came from, or was just written to, the 60s explore cache. Pair it with fresh_for_seconds to derive how much longer the body may be reused: fresh_for_seconds - age(computed_at). Excluded from the ETag validator, so a body recomputed with identical data keeps its validator. */
3187
+ computed_at?: string;
3188
+ /** How long the body computed at computed_at is good for, in seconds. Deliberately not pre-subtracted: a cached body cannot carry a number that changes while it sits in the cache. Excluded from the ETag validator. */
3189
+ fresh_for_seconds?: number;
3190
+ };
3191
+ getAccountIdentity: AccountIdentity;
3192
+ getApiDiscovery: {
3193
+ object: "api_discovery";
3194
+ data: OperationData["getApiDiscovery"];
3195
+ meta: ResponseMeta;
3196
+ };
3197
+ getDailyReportSnapshot: {
3198
+ object: "report_snapshot";
3199
+ data: OperationData["getDailyReportSnapshot"];
3200
+ meta: ResponseMeta;
3201
+ };
3202
+ getEventReplaySince: {
3203
+ object: "event_replay";
3204
+ data: OperationData["getEventReplaySince"];
3205
+ has_more: boolean;
3206
+ next_cursor: string;
3207
+ meta: EventReplayMeta;
3208
+ };
3209
+ getHealth: {
3210
+ object: "health";
3211
+ data: OperationData["getHealth"];
3212
+ meta: ResponseMeta;
3213
+ };
3214
+ getInsiderRadarFlag: {
3215
+ object: "radar_flag";
3216
+ data: OperationData["getInsiderRadarFlag"];
3217
+ meta: ResponseMeta;
3218
+ };
3219
+ getMarketCandles: {
3220
+ object: "market_candles";
3221
+ data: OperationData["getMarketCandles"];
3222
+ meta: ResponseMeta;
3223
+ };
3224
+ getMarketContextMarkdown: string;
3225
+ getMarketHolders: {
3226
+ object: "list";
3227
+ data: OperationData["getMarketHolders"];
3228
+ has_more: boolean;
3229
+ /** Absent on the last page. */
3230
+ next_cursor?: string;
3231
+ /** Holders matching the request's `outcome` and `min_grade` filters across every page. */
3232
+ total?: number;
3233
+ market: MarketHoldersMarket;
3234
+ scan: MarketHoldersScan;
3235
+ totals: MarketHoldersTotals;
3236
+ meta: ResponseMeta;
3237
+ };
3238
+ getMarketIntel: {
3239
+ object: "market_intel";
3240
+ data: OperationData["getMarketIntel"];
3241
+ meta: ResponseMeta;
3242
+ };
3243
+ getMarketSnapshot: {
3244
+ object: "market_snapshot";
3245
+ data: OperationData["getMarketSnapshot"];
3246
+ meta: ResponseMeta;
3247
+ };
3248
+ getMonthlyReportSnapshot: {
3249
+ object: "report_snapshot";
3250
+ data: OperationData["getMonthlyReportSnapshot"];
3251
+ meta: ResponseMeta;
3252
+ };
3253
+ getPickOfTheDay: {
3254
+ object: "pick_of_the_day";
3255
+ data: OperationData["getPickOfTheDay"];
3256
+ meta: ResponseMeta;
3257
+ };
3258
+ getPickOfTheDayArchive: {
3259
+ object: "pick_of_the_day_archive";
3260
+ data: OperationData["getPickOfTheDayArchive"];
3261
+ meta: ResponseMeta;
3262
+ };
3263
+ getPickOfTheDayLedger: {
3264
+ object: "pick_of_the_day_ledger";
3265
+ data: OperationData["getPickOfTheDayLedger"];
3266
+ meta: ResponseMeta;
3267
+ };
3268
+ getPlatforms: {
3269
+ object: "platforms";
3270
+ data: OperationData["getPlatforms"];
3271
+ meta: ResponseMeta;
3272
+ };
3273
+ getPositionTimeline: {
3274
+ object: "list";
3275
+ data: OperationData["getPositionTimeline"];
3276
+ has_more: boolean;
3277
+ next_cursor?: string;
3278
+ /** Total matching rows when the read model exposes a count; the key is absent when it does not. */
3279
+ total?: number;
3280
+ meta: ResponseMeta;
3281
+ };
3282
+ getPositionTimelineById: {
3283
+ object: "list";
3284
+ data: OperationData["getPositionTimelineById"];
3285
+ has_more: boolean;
3286
+ next_cursor?: string;
3287
+ /** Total matching rows when the read model exposes a count; the key is absent when it does not. */
3288
+ total?: number;
3289
+ meta: ResponseMeta;
3290
+ };
3291
+ getReports: {
3292
+ object: "report_snapshot";
3293
+ data: OperationData["getReports"];
3294
+ meta: ResponseMeta;
3295
+ };
3296
+ getStream: string;
3297
+ getTrader: {
3298
+ object: "trader";
3299
+ data: OperationData["getTrader"];
3300
+ meta: ResponseMeta;
3301
+ };
3302
+ getTraderCategoryRecords: {
3303
+ object: "trader_category_records";
3304
+ data: OperationData["getTraderCategoryRecords"];
3305
+ meta: ResponseMeta;
3306
+ };
3307
+ getTraderContext: {
3308
+ object: "trader_context";
3309
+ data: OperationData["getTraderContext"];
3310
+ meta: ResponseMeta;
3311
+ };
3312
+ getTraderContextMarkdown: string;
3313
+ getTraderExportSnapshot: {
3314
+ object: "trader_export_snapshot";
3315
+ data: OperationData["getTraderExportSnapshot"];
3316
+ meta: ResponseMeta;
3317
+ };
3318
+ getTraderExportStatus: TraderExportJob;
3319
+ getTraderPnl: {
3320
+ object: "trader_pnl";
3321
+ data: OperationData["getTraderPnl"];
3322
+ meta: ResponseMeta;
3323
+ };
3324
+ getUsage: Usage;
3325
+ getWebhook: {
3326
+ object: "webhook";
3327
+ data: OperationData["getWebhook"];
3328
+ meta: ResponseMeta;
3329
+ };
3330
+ getWeeklyReportSnapshot: {
3331
+ object: "report_snapshot";
3332
+ data: OperationData["getWeeklyReportSnapshot"];
3333
+ meta: ResponseMeta;
3334
+ };
3335
+ getWhaleTrade: {
3336
+ object: "whale_trade";
3337
+ data: OperationData["getWhaleTrade"];
3338
+ meta: ResponseMeta;
3339
+ };
3340
+ listInsiderRadar: {
3341
+ object: "list";
3342
+ data: OperationData["listInsiderRadar"];
3343
+ has_more: boolean;
3344
+ next_cursor?: string;
3345
+ /** Total matching rows when the read model exposes a count; the key is absent when it does not. */
3346
+ total?: number;
3347
+ meta: ResponseMeta;
3348
+ };
3349
+ listLargePositions: {
3350
+ object: "list";
3351
+ data: OperationData["listLargePositions"];
3352
+ has_more: boolean;
3353
+ /** Opaque cursor for the next page; absent on the last page. */
3354
+ next_cursor?: string;
3355
+ /** Total ranked rows when the read model exposes a count; may be absent. */
3356
+ total?: number;
3357
+ meta: ResponseMeta;
3358
+ };
3359
+ listLeaderboard: {
3360
+ object: "list";
3361
+ data: OperationData["listLeaderboard"];
3362
+ has_more: boolean;
3363
+ next_cursor?: string;
3364
+ /** Total matching rows when the read model exposes a count; the key is absent when it does not. */
3365
+ total?: number;
3366
+ meta: ResponseMeta;
3367
+ };
3368
+ listPositions: {
3369
+ object: "list";
3370
+ data: OperationData["listPositions"];
3371
+ has_more: boolean;
3372
+ next_cursor?: string;
3373
+ /** Total matching rows when the read model exposes a count; the key is absent when it does not. */
3374
+ total?: number;
3375
+ meta: ResponseMeta;
3376
+ };
3377
+ listSharpMoneyFlows: {
3378
+ object: "list";
3379
+ data: OperationData["listSharpMoneyFlows"];
3380
+ has_more: boolean;
3381
+ next_cursor?: string;
3382
+ total?: number;
3383
+ meta: ResponseMeta;
3384
+ };
3385
+ listSmartMoneyFlows: {
3386
+ object: "list";
3387
+ data: OperationData["listSmartMoneyFlows"];
3388
+ has_more: boolean;
3389
+ next_cursor?: string;
3390
+ total?: number;
3391
+ meta: ResponseMeta;
3392
+ };
3393
+ listSportsEdgeObservations: {
3394
+ object: "list";
3395
+ data: OperationData["listSportsEdgeObservations"];
3396
+ has_more: boolean;
3397
+ next_cursor?: string;
3398
+ /** Completion time of the shared observation snapshot pinned by the cursor. */
3399
+ snapshot_as_of: string;
3400
+ /** True when an operational failure or unknown provider-board, holder, directional, reconciliation, or internal completeness state made this snapshot partial. This is snapshot-wide and can retain degradation that the funnel's one-terminal-per-input accounting cannot represent. Intentional bounded capacity_limited rows remain fully accounted in the funnel and do not by themselves set this field. */
3401
+ degraded: boolean;
3402
+ funnel: SportsEdgeFunnelReport;
3403
+ meta: ResponseMeta;
3404
+ };
3405
+ listSportsEdgeSignals: {
3406
+ object: "list";
3407
+ data: OperationData["listSportsEdgeSignals"];
3408
+ has_more: boolean;
3409
+ next_cursor?: string;
3410
+ total?: number;
3411
+ meta: ResponseMeta;
3412
+ };
3413
+ listTrendingWallets: {
3414
+ object: "list";
3415
+ data: OperationData["listTrendingWallets"];
3416
+ has_more: boolean;
3417
+ /** Opaque cursor for the next page; absent on the last page. */
3418
+ next_cursor?: string;
3419
+ /** Total ranked rows when the read model exposes a count; may be absent. */
3420
+ total?: number;
3421
+ meta: ResponseMeta;
3422
+ };
3423
+ listWebhookDeliveries: {
3424
+ object: "list";
3425
+ data: OperationData["listWebhookDeliveries"];
3426
+ has_more: boolean;
3427
+ next_cursor?: string;
3428
+ total?: number;
3429
+ meta: ResponseMeta;
3430
+ };
3431
+ listWebhookEvents: {
3432
+ object: "list";
3433
+ data: OperationData["listWebhookEvents"];
3434
+ has_more: boolean;
3435
+ next_cursor?: string;
3436
+ total?: number;
3437
+ meta: ResponseMeta;
3438
+ };
3439
+ listWebhooks: {
3440
+ object: "list";
3441
+ data: OperationData["listWebhooks"];
3442
+ has_more: boolean;
3443
+ next_cursor?: string;
3444
+ total?: number;
3445
+ meta: ResponseMeta;
3446
+ };
3447
+ listWhaleTradeCounterpartyExecutions: {
3448
+ object: "counterparty_analysis";
3449
+ data: OperationData["listWhaleTradeCounterpartyExecutions"];
3450
+ meta: ResponseMeta;
3451
+ };
3452
+ listWhaleTradeCounterpartyMakers: {
3453
+ object: "counterparty_maker_page";
3454
+ data: OperationData["listWhaleTradeCounterpartyMakers"];
3455
+ meta: ResponseMeta;
3456
+ };
3457
+ listWhaleTradeHistory: {
3458
+ object: "list";
3459
+ data: OperationData["listWhaleTradeHistory"];
3460
+ has_more: boolean;
3461
+ next_cursor?: string;
3462
+ /** Total matching rows when the read model exposes a count; the key is absent when it does not. */
3463
+ total?: number;
3464
+ meta: WhaleTradeHistoryMeta;
3465
+ };
3466
+ listWhaleTrades: {
3467
+ object: "list";
3468
+ data: OperationData["listWhaleTrades"];
3469
+ has_more: boolean;
3470
+ next_cursor?: string;
3471
+ /** Total matching rows when the read model exposes a count; the key is absent when it does not. */
3472
+ total?: number;
3473
+ meta: ResponseMeta;
3474
+ };
3475
+ prepareWebhookSecret: {
3476
+ object: "webhook";
3477
+ data: OperationData["prepareWebhookSecret"];
3478
+ meta: ResponseMeta;
3479
+ };
3480
+ redeliverWebhookDelivery: {
3481
+ object: "webhook_delivery";
3482
+ data: OperationData["redeliverWebhookDelivery"];
3483
+ meta: ResponseMeta;
3484
+ };
3485
+ registerAgent: {
3486
+ object: "agent_registration";
3487
+ data: OperationData["registerAgent"];
3488
+ meta: ResponseMeta;
3489
+ };
3490
+ retireWebhookSecret: {
3491
+ object: "webhook";
3492
+ data: OperationData["retireWebhookSecret"];
3493
+ meta: ResponseMeta;
3494
+ };
3495
+ rotateWebhookSecret: {
3496
+ object: "webhook";
3497
+ data: OperationData["rotateWebhookSecret"];
3498
+ meta: ResponseMeta;
3499
+ };
3500
+ searchContent: {
3501
+ object: "list";
3502
+ data: OperationData["searchContent"];
3503
+ has_more: false;
3504
+ /** Omitted because content search is a bounded one-page result. */
3505
+ next_cursor?: string;
3506
+ /** Absent because content search is a bounded relevance result and does not run a count query. */
3507
+ total?: number;
3508
+ meta: ResponseMeta;
3509
+ };
3510
+ searchMarkets: {
3511
+ object: "list";
3512
+ data: OperationData["searchMarkets"];
3513
+ has_more: boolean;
3514
+ next_cursor?: string;
3515
+ /** Total matching rows when the read model exposes a count; the key is absent when it does not. */
3516
+ total?: number;
3517
+ meta: ResponseMeta;
3518
+ };
3519
+ submitTraderExport: TraderExportJob;
3520
+ updateWebhook: {
3521
+ object: "webhook";
3522
+ data: OperationData["updateWebhook"];
3523
+ meta: ResponseMeta;
3524
+ };
3525
+ verifyWebhook: {
3526
+ object: "webhook";
3527
+ data: OperationData["verifyWebhook"];
3528
+ meta: ResponseMeta;
3529
+ };
3530
+ }
2425
3531
  //# sourceMappingURL=schema.d.ts.map