@0xinsider/mcp 2.1.0 → 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 (92) hide show
  1. package/README.md +25 -6
  2. package/dist/cli-lib.d.ts +1 -0
  3. package/dist/cli-lib.d.ts.map +1 -1
  4. package/dist/cli-lib.js +48 -8
  5. package/dist/cli-lib.js.map +1 -1
  6. package/dist/client.d.ts +33 -2
  7. package/dist/client.d.ts.map +1 -1
  8. package/dist/client.js +42 -4
  9. package/dist/client.js.map +1 -1
  10. package/dist/constants.d.ts +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/product-cli/client.d.ts +3 -2
  13. package/dist/product-cli/client.d.ts.map +1 -1
  14. package/dist/product-cli/client.js.map +1 -1
  15. package/dist/sdk/client.d.ts +690 -133
  16. package/dist/sdk/client.d.ts.map +1 -1
  17. package/dist/sdk/client.js +699 -125
  18. package/dist/sdk/client.js.map +1 -1
  19. package/dist/sdk/errors.d.ts +42 -4
  20. package/dist/sdk/errors.d.ts.map +1 -1
  21. package/dist/sdk/errors.js +103 -2
  22. package/dist/sdk/errors.js.map +1 -1
  23. package/dist/sdk/index.d.ts +9 -8
  24. package/dist/sdk/index.d.ts.map +1 -1
  25. package/dist/sdk/index.js +6 -4
  26. package/dist/sdk/index.js.map +1 -1
  27. package/dist/sdk/pagination.d.ts +133 -15
  28. package/dist/sdk/pagination.d.ts.map +1 -1
  29. package/dist/sdk/pagination.js +132 -34
  30. package/dist/sdk/pagination.js.map +1 -1
  31. package/dist/sdk/retry.d.ts +68 -0
  32. package/dist/sdk/retry.d.ts.map +1 -0
  33. package/dist/sdk/retry.js +125 -0
  34. package/dist/sdk/retry.js.map +1 -0
  35. package/dist/sdk/schema.d.ts +1381 -439
  36. package/dist/sdk/schema.d.ts.map +1 -1
  37. package/dist/sdk/stream.d.ts +318 -8
  38. package/dist/sdk/stream.d.ts.map +1 -1
  39. package/dist/sdk/stream.js +503 -56
  40. package/dist/sdk/stream.js.map +1 -1
  41. package/dist/sdk/webhooks.d.ts +18 -3
  42. package/dist/sdk/webhooks.d.ts.map +1 -1
  43. package/dist/sdk/webhooks.js +13 -1
  44. package/dist/sdk/webhooks.js.map +1 -1
  45. package/dist/tools/explore-markets.d.ts.map +1 -1
  46. package/dist/tools/explore-markets.js +2 -5
  47. package/dist/tools/explore-markets.js.map +1 -1
  48. package/dist/tools/get-insider-radar.d.ts.map +1 -1
  49. package/dist/tools/get-insider-radar.js +3 -10
  50. package/dist/tools/get-insider-radar.js.map +1 -1
  51. package/dist/tools/get-large-positions.d.ts.map +1 -1
  52. package/dist/tools/get-large-positions.js +3 -10
  53. package/dist/tools/get-large-positions.js.map +1 -1
  54. package/dist/tools/get-leaderboard.d.ts.map +1 -1
  55. package/dist/tools/get-leaderboard.js +3 -10
  56. package/dist/tools/get-leaderboard.js.map +1 -1
  57. package/dist/tools/get-market-intel.d.ts.map +1 -1
  58. package/dist/tools/get-market-intel.js +3 -6
  59. package/dist/tools/get-market-intel.js.map +1 -1
  60. package/dist/tools/get-position-timeline.d.ts.map +1 -1
  61. package/dist/tools/get-position-timeline.js +3 -10
  62. package/dist/tools/get-position-timeline.js.map +1 -1
  63. package/dist/tools/get-positions.d.ts +2 -0
  64. package/dist/tools/get-positions.d.ts.map +1 -1
  65. package/dist/tools/get-positions.js +8 -11
  66. package/dist/tools/get-positions.js.map +1 -1
  67. package/dist/tools/get-trader-pnl.d.ts.map +1 -1
  68. package/dist/tools/get-trader-pnl.js +3 -6
  69. package/dist/tools/get-trader-pnl.js.map +1 -1
  70. package/dist/tools/get-trader.d.ts.map +1 -1
  71. package/dist/tools/get-trader.js +3 -6
  72. package/dist/tools/get-trader.js.map +1 -1
  73. package/dist/tools/get-trending-wallets.d.ts.map +1 -1
  74. package/dist/tools/get-trending-wallets.js +3 -10
  75. package/dist/tools/get-trending-wallets.js.map +1 -1
  76. package/dist/tools/get-whale-trades.d.ts.map +1 -1
  77. package/dist/tools/get-whale-trades.js +4 -11
  78. package/dist/tools/get-whale-trades.js.map +1 -1
  79. package/dist/tools/pick-of-the-day.d.ts.map +1 -1
  80. package/dist/tools/pick-of-the-day.js +5 -21
  81. package/dist/tools/pick-of-the-day.js.map +1 -1
  82. package/dist/tools/read-parity.d.ts.map +1 -1
  83. package/dist/tools/read-parity.js +36 -44
  84. package/dist/tools/read-parity.js.map +1 -1
  85. package/dist/tools/result.d.ts +31 -0
  86. package/dist/tools/result.d.ts.map +1 -0
  87. package/dist/tools/result.js +70 -0
  88. package/dist/tools/result.js.map +1 -0
  89. package/dist/tools/search-markets.d.ts.map +1 -1
  90. package/dist/tools/search-markets.js +16 -11
  91. package/dist/tools/search-markets.js.map +1 -1
  92. 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,16 +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;
225
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. */
226
236
  last_traded_at?: string;
227
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/`. */
228
- profile_segment?: string | null;
238
+ profile_segment?: string;
229
239
  maker_fill_count: number;
230
240
  /** Exact decimal shares. */
231
241
  filled_shares: string;
@@ -242,15 +252,29 @@ export type CreateWebhookRequest = {
242
252
  event_types: WebhookEventType[];
243
253
  };
244
254
  export type EventReplayEvent = {
245
- /** 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. */
246
256
  id: string;
247
257
  type: "whale_trades_inserted";
248
- /** 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. */
249
259
  cursor: string;
250
- /** 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. */
251
261
  sequence: number;
252
262
  published_at: string;
253
- 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;
254
278
  source: EventReplaySource;
255
279
  freshness: EventReplayFreshness;
256
280
  };
@@ -259,18 +283,36 @@ export type EventReplayFreshness = {
259
283
  observed_at: string;
260
284
  };
261
285
  export type EventReplayMeta = {
262
- /** 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. */
263
287
  request_id: string;
264
288
  cached: boolean;
265
- cache_age_s?: number | null;
289
+ cache_age_s?: number;
266
290
  /** Advisory request weight (relative compute cost). 1 for simple reads; higher for heavier endpoints. Not a credit/price. */
267
291
  cost: number;
268
292
  replay: {
293
+ /** The request cursor in canonical form (an id-only cursor is re-encoded), or the zero position when omitted. */
269
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. */
270
296
  to_cursor: string;
297
+ /** whale_alerts.id component of the request cursor (0 when omitted). */
271
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. */
272
300
  to_sequence: number;
273
- 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"[];
274
316
  };
275
317
  retention: {
276
318
  status: "durable_database";
@@ -278,6 +320,7 @@ export type EventReplayMeta = {
278
320
  cursor_expired: false;
279
321
  };
280
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. */
281
324
  status: "complete" | "caught_up";
282
325
  reason: string;
283
326
  };
@@ -302,13 +345,13 @@ export type ExploreGroup = {
302
345
  type: "group";
303
346
  event_slug: string;
304
347
  parent_title: string;
305
- image?: string | null;
306
- platform?: string | null;
307
- category?: string | null;
348
+ image: string | null;
349
+ platform: string | null;
350
+ category: string | null;
308
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. */
309
352
  markets: ExploreMarket[];
310
- rep_volume?: number | null;
311
- rep_whales?: number | null;
353
+ rep_volume: number | null;
354
+ rep_whales: number | null;
312
355
  };
313
356
  export type ExploreMarket = {
314
357
  id: string;
@@ -316,57 +359,57 @@ export type ExploreMarket = {
316
359
  /** Non-empty market title. */
317
360
  title: string;
318
361
  /** Provider-native market slug. */
319
- slug?: string | null;
362
+ slug: string | null;
320
363
  /** First-party market page slug used for internal links. */
321
- url_slug?: string | null;
322
- image?: string | null;
323
- icon?: string | null;
324
- category?: string | null;
325
- platform?: string | null;
364
+ url_slug: string | null;
365
+ image: string | null;
366
+ icon: string | null;
367
+ category: string | null;
368
+ platform: string | null;
326
369
  status: "active" | "closed";
327
- volume?: number | null;
328
- liquidity?: number | null;
329
- whale_trade_count?: number | null;
330
- whale_distinct_wallets?: number | null;
331
- whale_total_usd?: number | null;
332
- whale_last_trade_at?: string | null;
333
- end_date?: string | null;
334
- created_at?: string | null;
335
- 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;
336
379
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the YES outcome; null when unavailable (e.g. unsynced markets). */
337
- token_id_yes?: string | null;
338
- outcome_no?: string | null;
380
+ token_id_yes: string | null;
381
+ outcome_no: string | null;
339
382
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the NO outcome; null when unavailable (e.g. unsynced markets). */
340
- token_id_no?: string | null;
341
- event_slug?: string | null;
342
- smart_score?: number | null;
343
- smart_count?: number | null;
344
- 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;
345
388
  /** Display label for the YES/outcome_index=0 side, enriched from provider outcome metadata when available. */
346
- outcome_yes_label?: string | null;
389
+ outcome_yes_label: string | null;
347
390
  /** Display label for the NO/outcome_index=1 side, enriched from provider outcome metadata when available. */
348
- outcome_no_label?: string | null;
391
+ outcome_no_label: string | null;
349
392
  /** Provider-owned YES/outcome_index=0 identifier when available for trade-ticket wiring. */
350
- outcome_yes_provider_id?: number | null;
393
+ outcome_yes_provider_id: number | null;
351
394
  /** Provider-owned NO/outcome_index=1 identifier when available for trade-ticket wiring. */
352
- outcome_no_provider_id?: number | null;
353
- open_interest?: number | null;
354
- oi_change_pct?: number | null;
355
- price_points?: number[][] | null;
356
- no_price_points?: number[][] | null;
357
- last_price?: number | null;
358
- no_last_price?: number | null;
359
- change_pct_24h?: number | null;
360
- 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;
361
404
  /** Backend-owned deterministic market discovery score used by the hot sort. */
362
- discover_score?: number | null;
405
+ discover_score: number | null;
363
406
  score_components?: {
364
- volume_signal?: number | null;
365
- whale_signal?: number | null;
366
- liquidity_signal?: number | null;
367
- recency_signal?: number | null;
368
- smart_money_signal?: number | null;
369
- 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;
370
413
  missing_price_penalty: number;
371
414
  };
372
415
  freshness?: {
@@ -390,18 +433,18 @@ export type ExportCounts = {
390
433
  estimated_size_mb: number;
391
434
  };
392
435
  export type ExportSourceRange = {
393
- first_pnl_date?: string | null;
394
- last_pnl_date?: string | null;
395
- latest_trade_at?: string | null;
396
- 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;
397
440
  };
398
441
  export type ExportVolumeReconciliation = {
399
442
  /** Verified full-history both-sides USD cash volume. Null without coverage; the local activity numerator may cover only a subset of history. */
400
- provider_lifetime_volume?: number | null;
443
+ provider_lifetime_volume: number | null;
401
444
  exported_activity_volume: number;
402
445
  exported_market_cost_basis: number;
403
- provider_activity_volume_gap?: number | null;
404
- activity_volume_coverage?: number | null;
446
+ provider_activity_volume_gap: number | null;
447
+ activity_volume_coverage: number | null;
405
448
  };
406
449
  /** Current category evidence, independent of the global grade. Pick of the Day stamps only the served display roster; frozen entry snapshots remain unchanged. */
407
450
  export type HolderCategoryEvidence = {
@@ -436,14 +479,14 @@ export type LargePosition = {
436
479
  id: string;
437
480
  /** Provider discriminator. Always polymarket. */
438
481
  platform: "polymarket";
439
- /** Provider currentValue in USD for the outcome named by outcome_label / token_id, and for that outcome only. Null means the provider supplied no value for this leg, not a zero position. combined_value_usd carries the wallet's whole-market total. */
440
- total_size_usd?: number | null;
441
- /** Provider unrealized mark-to-market P&L (Polymarket cashPnl) for that same one outcome. Null means unavailable, not break-even. */
442
- 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;
443
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. */
444
- combined_value_usd?: number | null;
487
+ combined_value_usd?: number;
445
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. */
446
- combined_unrealized_pnl?: number | null;
489
+ combined_unrealized_pnl?: number;
447
490
  /** Whether the wallet holds shares on both outcomes of this market. */
448
491
  is_two_sided: boolean;
449
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. */
@@ -451,76 +494,77 @@ export type LargePosition = {
451
494
  /** 0 = Yes, 1 = No. */
452
495
  outcome_index: number;
453
496
  /** The market's label for this outcome. */
454
- outcome_label?: string | null;
497
+ outcome_label?: string;
455
498
  /** Polymarket CLOB token id for this outcome; null for an unsynced market. */
456
499
  token_id: string | null;
457
500
  /** Shares held on this outcome. */
458
501
  share_count: number;
459
502
  /** Provider average entry price for this outcome. */
460
- avg_entry_price?: number | null;
503
+ avg_entry_price?: number;
461
504
  /** Provider mark price for this outcome. */
462
- current_price?: number | null;
463
- /** Provider currentValue for this outcome. Null means unavailable, not zero. */
464
- value_usd?: number | null;
465
- /** Provider unrealized P&L for this outcome. Null means unavailable, not break-even. */
466
- unrealized_pnl?: number | null;
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;
467
510
  })[];
468
511
  /** Live share count for this position. */
469
512
  share_count: number;
470
513
  /** Volume-weighted entry price. */
471
- avg_entry_price?: number | null;
514
+ avg_entry_price?: number;
472
515
  /** Latest provider mark price for the position's token. */
473
- current_price?: number | null;
516
+ current_price?: number;
474
517
  /** Backend-resolved outcome label (provider outcome, else Yes/No from the binary index). */
475
- outcome_label?: string | null;
518
+ outcome_label?: string;
476
519
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets). */
477
- token_id?: string | null;
520
+ token_id: string | null;
478
521
  /** Legs collapsed into this representative row for one (wallet, event, outcome side) group. 1 means standalone. */
479
522
  event_leg_count: number;
480
- /** Sum of the collapsed sibling legs' own holding values for this (wallet, event) group; equals total_size_usd when event_leg_count = 1, and null when any member's value is unknown. */
481
- 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;
482
525
  first_seen_at: string;
483
526
  last_updated_at: string;
484
527
  trader: {
485
528
  /** Prefixed ID (`trd_...`). */
486
529
  id: string;
487
530
  address: string;
488
- username?: string | null;
531
+ username?: string;
489
532
  grade?: "S" | "A" | "B" | "C" | "D" | "F";
490
- win_rate?: number | null;
533
+ win_rate?: number;
491
534
  /** Trader lifetime realized P&L across all markets. */
492
- pnl?: number | null;
493
- markets_traded?: number | null;
535
+ pnl?: number;
536
+ markets_traded?: number;
494
537
  };
495
538
  market: {
496
539
  /** Prefixed ID (`mkt_...`). */
497
540
  id: string;
498
541
  condition_id: string;
499
- title?: string | null;
500
- slug?: string | null;
501
- event_slug?: string | null;
502
- category?: string | null;
542
+ title?: string;
543
+ slug?: string;
544
+ event_slug?: string;
545
+ category?: string;
503
546
  };
504
547
  };
505
548
  export type LeaderboardEntry = {
506
549
  id: string;
507
550
  address: string;
508
- username?: string | null;
509
- grade?: string | null;
510
- /** 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. */
511
554
  streak_tier?: "hot" | "rising" | "neutral" | "cooling" | "cold";
512
- score?: number | null;
555
+ score?: number;
513
556
  /** All-time P&L in USD (total_pnl), including unrealized open positions. Kept for back-compat; prefer realized_pnl for the banked figure. */
514
- pnl?: number | null;
557
+ pnl?: number;
515
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. */
516
- realized_pnl?: number | null;
559
+ realized_pnl?: number;
517
560
  /** Full-history both-sides USD cash volume from a verified Polymarket user-volume observation. Omitted without coverage. */
518
- volume?: number | null;
519
- markets_traded?: number | null;
520
- win_rate?: number | null;
521
- strategy_type?: string | null;
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;
522
566
  platform: string;
523
- last_active?: string | null;
567
+ last_active?: string;
524
568
  };
525
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). */
526
570
  export type MarketCandles = {
@@ -531,32 +575,127 @@ export type MarketCandles = {
531
575
  /** One entry per present provider token (YES first, then NO); empty when no tokens have been fetched yet. */
532
576
  outcomes: OutcomeCandles[];
533
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
+ };
534
673
  export type MarketIntel = {
535
674
  market: {
536
675
  id: string;
537
676
  condition_id: string;
538
677
  title: string;
539
- slug?: string | null;
540
- category?: string | null;
541
- platform?: string | null;
678
+ slug: string | null;
679
+ category: string | null;
680
+ platform: string | null;
542
681
  };
543
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. */
544
683
  sharp_money: {
545
684
  net_flow_usd: number;
546
685
  direction: "YES" | "NO";
547
686
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets). */
548
- token_id?: string | null;
687
+ token_id: string | null;
549
688
  whale_trade_count: number;
550
689
  buy_volume_usd: number;
551
690
  sell_volume_usd: number;
552
691
  top_positions: ({
553
692
  id: string;
554
693
  address: string;
555
- username?: string | null;
556
- grade?: string | null;
694
+ username: string | null;
695
+ grade: string | null;
557
696
  side: "YES" | "NO";
558
697
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets). */
559
- token_id?: string | null;
698
+ token_id: string | null;
560
699
  size_usd: number;
561
700
  })[];
562
701
  };
@@ -565,18 +704,18 @@ export type MarketIntel = {
565
704
  net_flow_usd: number;
566
705
  direction: "YES" | "NO";
567
706
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets). */
568
- token_id?: string | null;
707
+ token_id: string | null;
569
708
  whale_trade_count: number;
570
709
  buy_volume_usd: number;
571
710
  sell_volume_usd: number;
572
711
  top_positions: ({
573
712
  id: string;
574
713
  address: string;
575
- username?: string | null;
576
- grade?: string | null;
714
+ username: string | null;
715
+ grade: string | null;
577
716
  side: "YES" | "NO";
578
717
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets). */
579
- token_id?: string | null;
718
+ token_id: string | null;
580
719
  size_usd: number;
581
720
  })[];
582
721
  };
@@ -586,9 +725,9 @@ export type MarketSearchResult = {
586
725
  id: string;
587
726
  condition_id: string;
588
727
  title: string;
589
- slug?: string | null;
590
- category?: string | null;
591
- platform?: string | null;
728
+ slug: string | null;
729
+ category: string | null;
730
+ platform: string | null;
592
731
  status: "active" | "closed";
593
732
  };
594
733
  export type MarketSnapshot = {
@@ -596,45 +735,45 @@ export type MarketSnapshot = {
596
735
  id: string;
597
736
  condition_id: string;
598
737
  provider: string;
599
- title?: string | null;
600
- slug?: string | null;
601
- page_slug?: string | null;
602
- event_slug?: string | null;
603
- 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;
604
743
  status: "active" | "closed";
605
- description?: string | null;
606
- image?: string | null;
744
+ description: string | null;
745
+ image: string | null;
607
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. */
608
- series_slug?: string | null;
609
- market_type?: string | null;
610
- market_result?: string | null;
611
- created_at?: string | null;
612
- end_date?: string | null;
613
- 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;
614
753
  };
615
754
  outcomes: ({
616
755
  side: "yes" | "no";
617
756
  label: string;
618
- token_id?: string | null;
619
- current_price?: number | null;
757
+ token_id?: string;
758
+ current_price?: number;
620
759
  top_of_book: MarketSnapshotTopOfBook;
621
760
  })[];
622
761
  liquidity: {
623
762
  source: string;
624
- volume_usd?: number | null;
625
- liquidity_usd?: number | null;
626
- volume_24h_usd?: number | null;
763
+ volume_usd: number | null;
764
+ liquidity_usd: number | null;
765
+ volume_24h_usd: number | null;
627
766
  /** Always null. Polymarket snapshot prices come from outcome top-of-book midpoints. */
628
- last_price?: number | null;
767
+ last_price: number | null;
629
768
  };
630
769
  sports: {
631
770
  status: "fresh" | "stale" | "not_live" | "unavailable";
632
771
  source: string;
633
- live_match_key?: string | null;
634
- live_league_key?: string | null;
772
+ live_match_key?: string;
773
+ live_league_key?: string;
635
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. */
636
- live_score?: Record<string, unknown> | null;
637
- reason?: string | null;
775
+ live_score?: Record<string, unknown>;
776
+ reason?: string;
638
777
  };
639
778
  freshness: {
640
779
  market_data: MarketSnapshotFreshness;
@@ -648,20 +787,20 @@ export type MarketSnapshot = {
648
787
  export type MarketSnapshotFreshness = {
649
788
  status: "fresh" | "stale" | "available" | "not_live" | "unavailable";
650
789
  source: string;
651
- as_of?: string | null;
790
+ as_of?: string;
652
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. */
653
- stale_after_s?: number | null;
654
- reason?: string | null;
792
+ stale_after_s?: number;
793
+ reason?: string;
655
794
  };
656
795
  export type MarketSnapshotTopOfBook = {
657
796
  status: "available" | "unavailable";
658
797
  source: string;
659
- best_bid?: number | null;
660
- best_ask?: number | null;
661
- spread_bps?: number | null;
662
- bid_depth_usdc?: number | null;
663
- ask_depth_usdc?: number | null;
664
- 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;
665
804
  };
666
805
  /** Price and spread trust metadata returned only when GET /api/v1/market/{condition_id}/snapshot includes expand=trust. */
667
806
  export type MarketSnapshotTrust = {
@@ -689,21 +828,23 @@ export type OutcomeCandles = {
689
828
  };
690
829
  export type PickHolder = {
691
830
  address: string;
692
- name?: string | null;
831
+ name: string | null;
693
832
  /** All-time trader grade (S, A, B, C, D, F). */
694
- grade?: string | null;
833
+ grade: string | null;
695
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. */
696
- profile_segment?: string | null;
835
+ profile_segment?: string;
697
836
  shares: number;
698
- /** 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. */
699
- category_win_rate?: number | null;
700
- /** 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, 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. */
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. */
701
840
  category_win_record?: {
702
841
  /** Resolved markets in the category that this wallet closed with a profit. */
703
842
  wins: number;
704
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. */
705
844
  decided: number;
706
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;
707
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. */
708
849
  category_win_rate_status?: "measured" | "not_enough_data" | "unavailable";
709
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. */
@@ -722,7 +863,7 @@ export type PickOfTheDay = {
722
863
  /** Always 'full' for an authenticated Pro key. */
723
864
  state: "full";
724
865
  /** The pick's local publication date (YYYY-MM-DD). */
725
- pick_date: string;
866
+ pick_date?: string;
726
867
  /** Stable 1-based slot within the product day's ranked picks. */
727
868
  pick_rank?: number;
728
869
  /** The complete ranked picks for this product day, ordered by pick_rank. Thin days contain fewer items; the selector never fabricates rows. */
@@ -732,55 +873,59 @@ export type PickOfTheDay = {
732
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. */
733
874
  scheduled_picks?: ScheduledPickSlot[];
734
875
  /** Human-readable matchup (e.g. "Portugal vs. Uzbekistan"). */
735
- matchup: string;
876
+ matchup?: string;
736
877
  /** Frozen canonical calibration/report bucket (e.g. "Basketball", "MMA", or "Soccer"). Existing semantics are unchanged; presentation consumers should prefer display_category when present. */
737
- category: string;
878
+ category?: string;
738
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. */
739
880
  display_category?: string;
740
881
  /** Provider platform (e.g. "polymarket"). */
741
- platform: string;
882
+ platform?: string;
742
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. */
743
- release_at: string;
884
+ release_at?: string;
744
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`. */
745
- is_locked: boolean;
886
+ is_locked?: boolean;
746
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). */
747
888
  game_started?: boolean;
748
889
  /** Settlement outcome of the backed side; 'pending' until the market resolves. */
749
- outcome: "pending" | "win" | "loss" | "void";
890
+ outcome?: "pending" | "win" | "loss" | "void";
750
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. */
751
892
  outcome_display?: string;
752
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"). */
753
- pick_outcome_label: string;
754
- /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the backed outcome; null when unavailable (e.g. unsynced markets). */
755
- 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;
756
897
  /** The backed side phrased as a bet (e.g. "Portugal to win"). */
757
- position: string;
898
+ position?: string;
758
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. */
759
- side_summary: string;
900
+ side_summary?: string;
760
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. */
761
- smart_wallet_count: number;
902
+ smart_wallet_count?: number;
762
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. */
763
- top_grade?: string | null;
904
+ top_grade?: string;
764
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. */
765
- category_edge_pct?: number | null;
906
+ category_edge_pct?: number;
766
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). */
767
- category_edge_sample?: number | null;
908
+ category_edge_sample?: number;
768
909
  /** Recency-weighted graded-flow magnitude in USD; omitted when <= 0. */
769
- smart_usd?: number | null;
770
- /** Pre-game snapshot probability (0..1) for the backed side. */
771
- 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;
772
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. */
773
914
  entry_price_note?: string;
774
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. */
775
- odds_display?: string | null;
776
- /** Gross return on a $100 stake at the snapshotted price (100 / backed_price). */
777
- return_per_100?: number | null;
778
- /** 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. */
779
- payout_display?: string | null;
780
- /** 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. */
781
- 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;
782
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. */
783
- clv_status: string;
928
+ clv_status?: string;
784
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. */
785
930
  clv_basis?: string;
786
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. */
@@ -789,52 +934,52 @@ export type PickOfTheDay = {
789
934
  clv_display?: string;
790
935
  /** Backend-owned CLV formula text with the entry probability, close probability, and rounded result. Provider timestamps remain private. */
791
936
  clv_explanation?: string;
792
- /** 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. */
793
938
  unit_score?: number;
794
939
  /** Backend-formatted signed unit score, present exactly when unit_score is present. */
795
940
  unit_score_display?: string;
796
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. */
797
- sharp_pct?: number | null;
942
+ sharp_pct?: number;
798
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. */
799
- market_pct?: number | null;
800
- /** 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. */
801
- 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;
802
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. */
803
- directional_confidence?: number | null;
948
+ directional_confidence?: number;
804
949
  /** Graded backed-side holders read as one-way-committed on this game. */
805
- one_way_holder_count?: number | null;
950
+ one_way_holder_count?: number;
806
951
  /** Graded backed-side holders read as HEDGED across the game's markets. */
807
- hedged_holder_count?: number | null;
952
+ hedged_holder_count?: number;
808
953
  /** The one-way holders' share of the backed-side graded dollars (the confidence's numerator). */
809
- one_way_graded_usd?: number | null;
954
+ one_way_graded_usd?: number;
810
955
  /** Backed-side graded dollars the confidence is measured against (its denominator). */
811
- total_graded_usd?: number | null;
956
+ total_graded_usd?: number;
812
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. */
813
958
  qualifying_expert?: {
814
959
  /** Wallet address of the qualifying expert. */
815
960
  address: string;
816
961
  /** Provider display name, or null for an unnamed wallet. */
817
- name?: string | null;
962
+ name: string | null;
818
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. */
819
- grade?: string | null;
964
+ grade: string | null;
820
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. */
821
966
  canonical_category: string;
822
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. */
823
- win_rate?: number | null;
968
+ win_rate: number | null;
824
969
  /** Resolved markets in canonical_category behind win_rate. At least 10 by construction for a source=v1 expert; null with win_rate. */
825
- n_resolved?: number | null;
970
+ n_resolved: number | null;
826
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. */
827
972
  source?: "v1" | "v2";
828
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. */
829
- edge_lower_95?: number | null;
974
+ edge_lower_95?: number;
830
975
  /** Point estimate behind edge_lower_95. */
831
- edge_mean?: number | null;
976
+ edge_mean?: number;
832
977
  /** Independent canonical events behind the edge. At least 10 by construction for a v2 expert. */
833
- independent_event_count?: number | null;
978
+ independent_event_count?: number;
834
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. */
835
980
  position_usd: number;
836
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. */
837
- opposite_position_usd?: number | null;
982
+ opposite_position_usd?: number;
838
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. */
839
984
  stats_computed_at: string;
840
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. */
@@ -843,32 +988,32 @@ export type PickOfTheDay = {
843
988
  lane_probability?: number;
844
989
  /** Canonical provider probability pair branch; absent on standard experts. */
845
990
  lane_probability_source?: "p";
846
- } | null;
991
+ };
847
992
  trust?: PickTrust;
848
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. */
849
- traders?: number | null;
994
+ traders?: number;
850
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. */
851
- backed_sharp_usd?: number | null;
996
+ backed_sharp_usd?: number;
852
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. */
853
- holders?: PickHolder[] | null;
998
+ holders?: PickHolder[];
854
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. */
855
- display_holders?: PickHolder[] | null;
1000
+ display_holders?: PickHolder[];
856
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. */
857
- holder_count?: number | null;
1002
+ holder_count?: number;
858
1003
  /** Optional editorial note attached to the pick. */
859
- editorial_note?: string | null;
1004
+ editorial_note?: string;
860
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. */
861
- thesis: string;
1006
+ thesis?: string;
862
1007
  /** Canonical web market URL. */
863
- market_url?: string | null;
864
- /** The canonical /event game-page slug (one neutral page per game), null when the game has no neutral event page. */
865
- event_slug?: string | null;
866
- /** Backend-resolved /event destination slug for this pick's source market; null is an authoritative no-link decision. */
867
- 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;
868
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. */
869
1014
  sports_context?: PickSportsContext;
870
1015
  /** Risk disclaimer shown with every pick. */
871
- disclaimer: string;
1016
+ disclaimer?: string;
872
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. */
873
1018
  proof_pending_picks?: ProofPendingPickSlot[];
874
1019
  /** Frozen admission classification, full payload only. The specialist lane exempts two probability rejects and adds no rank bonus. Historical rows remain standard. */
@@ -917,30 +1062,40 @@ export type PickOfTheDayArchiveEntry = {
917
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. */
918
1063
  image_url?: string;
919
1064
  /** The backed side's outcome label. Omitted for a still-pending pick when the request is not from an authenticated Pro key. */
920
- pick_outcome_label?: string | null;
921
- /** 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. */
922
- 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;
923
1068
  /** Settlement outcome of the backed side; 'pending' until the market resolves. */
924
1069
  outcome: "pending" | "win" | "loss" | "void";
925
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. */
926
1071
  outcome_display?: string;
927
- /** 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. */
928
1077
  return_per_100?: number;
929
- /** 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. */
930
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;
931
1082
  /** Closing-line value toward the backed side, computed as (close / entry - 1) * 100. Omitted when the row is gated, ineligible, or not measured. */
932
1083
  clv_pct?: number;
933
1084
  /** Backend-formatted signed CLV percentage, present exactly when clv_pct is present. */
934
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;
935
1090
  /** Whether CLV applies. A visible resolved pick published after kickoff is not_applicable. */
936
1091
  clv_applicability?: "applicable" | "not_applicable";
937
- /** 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. */
938
1093
  clv_explanation?: string;
939
- /** Exact backend CLV capture disposition for this visible row. Pending and terminal provider or quality statuses are distinguishable; raw close evidence is never serialized. */
940
- 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;
941
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. */
942
1097
  clv_basis?: string;
943
- /** 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. */
944
1099
  unit_score?: number;
945
1100
  /** Backend-formatted signed unit score, present exactly when unit_score is present. */
946
1101
  unit_score_display?: string;
@@ -977,9 +1132,11 @@ export type PickOfTheDayHitRate = {
977
1132
  void: number;
978
1133
  /** Number of picks still pending resolution (excluded from the hit rate). */
979
1134
  pending: number;
980
- /** 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. */
981
1138
  net_profit_usd: number;
982
- /** 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. */
983
1140
  staked_usd: number;
984
1141
  /** Return on the staked amount as a percentage (net_profit_usd / staked_usd * 100, to 1 decimal); 0 when nothing is staked. */
985
1142
  roi_pct: number;
@@ -1031,7 +1188,7 @@ export type PickOfTheDayHitRate = {
1031
1188
  series?: {
1032
1189
  /** The decided pick's publish date (YYYY-MM-DD). */
1033
1190
  date: string;
1034
- /** 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. */
1035
1192
  net_profit_usd: number;
1036
1193
  /** Running rolling hit rate (wins / decided * 100, to 1 decimal) through this pick. */
1037
1194
  hit_rate_pct: number;
@@ -1143,51 +1300,51 @@ export type PickOfTheDayUncommittedPayload = {
1143
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. */
1144
1301
  export type PickSportsContext = {
1145
1302
  /** League or competition display name (e.g. "Premier League"). */
1146
- league_name?: string | null;
1303
+ league_name: string | null;
1147
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. */
1148
- competition_label?: string | null;
1305
+ competition_label?: string;
1149
1306
  /** League logo URL (provider-owned). */
1150
- league_logo?: string | null;
1307
+ league_logo: string | null;
1151
1308
  /** The team mapped to the market's YES outcome, or the parent-event home/first team when event_matchup is true. */
1152
- yes_team?: PickSportsTeam;
1309
+ yes_team: PickSportsTeam;
1153
1310
  /** The team mapped to the market's NO outcome, or the parent-event away/second team when event_matchup is true. */
1154
- no_team?: PickSportsTeam;
1155
- /** Provider game identifier (Polymarket Gamma gameId); omitted when null. */
1156
- 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;
1157
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. */
1158
1315
  event_matchup: boolean;
1159
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). */
1160
1317
  event_subject_team?: PickSportsTeam;
1161
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. */
1162
- matchup_title?: string | null;
1319
+ matchup_title?: string;
1163
1320
  };
1164
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. */
1165
1322
  export type PickSportsTeam = {
1166
1323
  /** Team display label as it appears on the market outcome (e.g. "Portugal"). */
1167
- label?: string | null;
1324
+ label: string | null;
1168
1325
  /** Abbreviated team label (e.g. "POR"). */
1169
- short_label?: string | null;
1326
+ short_label: string | null;
1170
1327
  /** Full team or competitor name (e.g. "Portugal national football team"). */
1171
- full_name?: string | null;
1328
+ full_name: string | null;
1172
1329
  /** Provider team identifier (Polymarket /teams id). */
1173
- provider_id?: number | null;
1330
+ provider_id: number | null;
1174
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. */
1175
- logo?: string | null;
1332
+ logo: string | null;
1176
1333
  /** Team brand color as a hex string (provider-owned). */
1177
- color?: string | null;
1334
+ color: string | null;
1178
1335
  /** Win-loss record as a display string (e.g. "12-4"). */
1179
- record?: string | null;
1336
+ record: string | null;
1180
1337
  /** Live or final score as a display string when the game is in play or settled. */
1181
- score?: string | null;
1338
+ score: string | null;
1182
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. */
1183
- headshot?: string | null;
1340
+ headshot?: string;
1184
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. */
1185
1342
  tour?: "atp" | "wta" | "itf";
1186
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. */
1187
1344
  sets?: ScoreCell[];
1188
1345
  format?: ScoreFormat;
1189
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. */
1190
- sets_won?: number | null;
1347
+ sets_won?: number;
1191
1348
  };
1192
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. */
1193
1350
  export type PickTrust = {
@@ -1219,33 +1376,33 @@ export type Position = {
1219
1376
  /** Binary outcome side. Non-binary positions are not surfaced on V1. */
1220
1377
  side: "YES" | "NO";
1221
1378
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets). */
1222
- token_id?: string | null;
1379
+ token_id: string | null;
1223
1380
  /** Live share count from the wallet_positions mirror. */
1224
1381
  shares: number;
1225
1382
  /** Volume-weighted entry price for this leg. */
1226
- avg_price?: number | null;
1383
+ avg_price?: number;
1227
1384
  /** Current mark-to-market value in USD (always non-null on V1 — pre-reconcile rows are excluded). */
1228
1385
  current_value_usd: number;
1229
- initial_value_usd?: number | null;
1386
+ initial_value_usd?: number;
1230
1387
  /** Unrealized P&L for the open position (Polymarket `cashPnl`). */
1231
- cash_pnl?: number | null;
1388
+ cash_pnl?: number;
1232
1389
  /** Closed-leg P&L rolled up (Polymarket `realizedPnl`). */
1233
- realized_pnl?: number | null;
1390
+ realized_pnl?: number;
1234
1391
  /** Max updated_at across mirror legs for this pair. */
1235
- last_reconciled_at?: string | null;
1392
+ last_reconciled_at?: string;
1236
1393
  /** Backend-computed staleness bucket derived from last_reconciled_at. */
1237
1394
  freshness: "fresh" | "refreshing" | "stale" | "unknown";
1238
1395
  trader: {
1239
1396
  /** Prefixed ID (`trd_...`). */
1240
1397
  id: string;
1241
1398
  address: string;
1242
- username?: string | null;
1399
+ username?: string;
1243
1400
  grade?: "S" | "A" | "B" | "C" | "D" | "F";
1244
1401
  /** Percentage 0-100. */
1245
- win_rate?: number | null;
1246
- pnl?: number | null;
1247
- markets?: number | null;
1248
- wallet_age_days?: number | null;
1402
+ win_rate?: number;
1403
+ pnl?: number;
1404
+ markets?: number;
1405
+ wallet_age_days?: number;
1249
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. */
1250
1407
  is_new_wallet: boolean;
1251
1408
  };
@@ -1254,13 +1411,13 @@ export type Position = {
1254
1411
  id: string;
1255
1412
  condition_id: string;
1256
1413
  title: string;
1257
- slug?: string | null;
1258
- event_slug?: string | null;
1414
+ slug?: string;
1415
+ event_slug?: string;
1259
1416
  /** Provider-backed market_canonical category. */
1260
- category?: string | null;
1417
+ category?: string;
1261
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. */
1262
- outcome_label?: string | null;
1263
- end_date?: string | null;
1419
+ outcome_label?: string;
1420
+ end_date?: string;
1264
1421
  };
1265
1422
  };
1266
1423
  export type PositionTimelineEvent = {
@@ -1272,7 +1429,7 @@ export type PositionTimelineEvent = {
1272
1429
  action: "buy" | "sell";
1273
1430
  outcome_side: "yes" | "no";
1274
1431
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets). */
1275
- token_id?: string | null;
1432
+ token_id: string | null;
1276
1433
  /** Signed share delta (+ on buy, − on sell). */
1277
1434
  amount_delta: number;
1278
1435
  /** Fill price in USDC per share, in [0,1]. */
@@ -1328,7 +1485,7 @@ export type RadarFlag = {
1328
1485
  trader: {
1329
1486
  id: string;
1330
1487
  address: string;
1331
- username?: string | null;
1488
+ username: string | null;
1332
1489
  };
1333
1490
  market: {
1334
1491
  id: string;
@@ -1338,13 +1495,13 @@ export type RadarFlag = {
1338
1495
  };
1339
1496
  scores: {
1340
1497
  /** Null because the live scorer does not record this component. */
1341
- timing?: number | null;
1498
+ timing: number | null;
1342
1499
  /** Null because the live scorer does not record this component. */
1343
- edge?: number | null;
1500
+ edge: number | null;
1344
1501
  /** Numeric evidence.size when recorded; otherwise null. */
1345
- size?: number | null;
1502
+ size: number | null;
1346
1503
  /** Numeric evidence.fresh when recorded; otherwise null. */
1347
- fresh_wallet?: number | null;
1504
+ fresh_wallet: number | null;
1348
1505
  };
1349
1506
  /** Stored whale_alerts.suspicion_signals JSON from the scorer. */
1350
1507
  evidence: unknown;
@@ -1352,44 +1509,45 @@ export type RadarFlag = {
1352
1509
  created_at: string;
1353
1510
  };
1354
1511
  export type ReportPayload = {
1355
- total_whale_trades?: number | null;
1356
- total_whale_volume?: number | null;
1357
- biggest_trade_size?: number | null;
1358
- active_traders?: number | null;
1359
- 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: ({
1360
1517
  /** Provider outcome label for the traded side. */
1361
- outcome?: string | null;
1518
+ outcome: string | null;
1362
1519
  /** Trade direction (BUY or SELL), not the outcome side. */
1363
- side?: string | null;
1520
+ side: string | null;
1364
1521
  /** Market title. */
1365
- title?: string | null;
1522
+ title: string | null;
1366
1523
  /** Trade size in USD. */
1367
- size?: number | null;
1524
+ size: number | null;
1368
1525
  /** Trade price in provider [0, 1] units. */
1369
- price?: number | null;
1526
+ price: number | null;
1370
1527
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the traded outcome; null when unavailable (e.g. unsynced markets). */
1371
- token_id?: string | null;
1528
+ token_id: string | null;
1372
1529
  /** Whale trade id. */
1373
- id?: number | null;
1530
+ id: number | null;
1374
1531
  /** Trade timestamp (UTC). */
1375
- trade_time?: string | null;
1532
+ trade_time: string | null;
1376
1533
  /** Provider market category. */
1377
- market_category?: string | null;
1534
+ market_category: string | null;
1378
1535
  /** Venue: polymarket. */
1379
- platform?: string | null;
1536
+ platform: string | null;
1380
1537
  /** Trader display name, when known. */
1381
- name?: string | null;
1538
+ name: string | null;
1382
1539
  /** Trader pseudonym, when no display name is known. */
1383
- pseudonym?: string | null;
1540
+ pseudonym: string | null;
1384
1541
  /** Trader grade (S-F) at snapshot time. */
1385
- trader_grade?: string | null;
1542
+ trader_grade: string | null;
1386
1543
  })[] | null;
1387
- categories?: Record<string, unknown>[] | null;
1388
- grade_distribution?: Record<string, unknown>[] | null;
1544
+ categories: Record<string, unknown>[] | null;
1545
+ grade_distribution: Record<string, unknown>[] | null;
1389
1546
  };
1390
1547
  export type ReportReconciliation = {
1391
1548
  volume_kind: "local_whale_activity_volume";
1392
- 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;
1393
1551
  notes: string;
1394
1552
  };
1395
1553
  export type ReportSnapshot = {
@@ -1407,17 +1565,17 @@ export type ReportSourceRange = {
1407
1565
  timezone: "UTC";
1408
1566
  };
1409
1567
  export type ResponseMeta = {
1410
- /** 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. */
1411
1569
  request_id: string;
1412
1570
  cached: boolean;
1413
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. */
1414
- cache_age_s?: number | null;
1572
+ cache_age_s?: number;
1415
1573
  /** Advisory request weight (relative compute cost). 1 for simple reads; higher for heavier endpoints. Not a credit/price. */
1416
1574
  cost: number;
1417
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. */
1418
- ranking_generation?: number | null;
1576
+ ranking_generation?: number;
1419
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. */
1420
- ranking_as_of?: string | null;
1578
+ ranking_as_of?: string;
1421
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. */
1422
1580
  directional_source?: "live" | "degraded";
1423
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. */
@@ -1476,7 +1634,7 @@ export type SmartMoneyFlowMarket = {
1476
1634
  net_flow_usd: number;
1477
1635
  direction: "YES" | "NO";
1478
1636
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets). */
1479
- token_id?: string | null;
1637
+ token_id: string | null;
1480
1638
  whale_trade_count: number;
1481
1639
  buy_volume_usd: number;
1482
1640
  sell_volume_usd: number;
@@ -1486,7 +1644,7 @@ export type SmartMoneyFlowMarket = {
1486
1644
  net_flow_usd: number;
1487
1645
  direction: "YES" | "NO";
1488
1646
  /** The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets). */
1489
- token_id?: string | null;
1647
+ token_id: string | null;
1490
1648
  whale_trade_count: number;
1491
1649
  buy_volume_usd: number;
1492
1650
  sell_volume_usd: number;
@@ -1494,17 +1652,28 @@ export type SmartMoneyFlowMarket = {
1494
1652
  timeframe: string;
1495
1653
  };
1496
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. */
1497
1656
  status: "complete" | "partial" | "empty";
1498
1657
  reason: string;
1499
1658
  expected_days: number;
1500
1659
  covered_days_with_whale_activity: number;
1501
1660
  };
1502
1661
  export type SnapshotState = {
1503
- /** 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. */
1504
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). */
1505
1667
  status: "final" | "rolling";
1506
1668
  generated_at: string;
1507
- 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;
1508
1677
  };
1509
1678
  /** Per-sport accountable funnel for the full observation snapshot, returned on every page. */
1510
1679
  export type SportsEdgeFunnelReport = {
@@ -1583,21 +1752,21 @@ export type SportsEdgeSignal = {
1583
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. */
1584
1753
  signal_created_at: string;
1585
1754
  /** Polymarket CLOB token id (ERC1155 asset id, decimal string) for the PILED outcome; null when unavailable. */
1586
- token_id?: string | null;
1755
+ token_id: string | null;
1587
1756
  /** Canonical sport bucket (e.g. Basketball, Tennis); null when the raw category has no canonical mapping. */
1588
- category?: string | null;
1757
+ category: string | null;
1589
1758
  /** Raw provider category as stored (e.g. NBA, EPL). */
1590
- raw_category?: string | null;
1591
- title?: string | null;
1592
- event_slug?: string | null;
1759
+ raw_category: string | null;
1760
+ title: string | null;
1761
+ event_slug: string | null;
1593
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. */
1594
- game_start_time?: string | null;
1763
+ game_start_time: string | null;
1595
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. */
1596
- piled_side?: string | null;
1765
+ piled_side: string | null;
1597
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. */
1598
1767
  piled_outcome_index: number;
1599
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. */
1600
- sharp_pct?: number | null;
1769
+ sharp_pct: number | null;
1601
1770
  /** Raw piled-side sharp-money USD. */
1602
1771
  backed_sharp_usd: number;
1603
1772
  /** S-grade graded holders on the piled side. */
@@ -1609,23 +1778,23 @@ export type SportsEdgeSignal = {
1609
1778
  /** Piled-side graded holder count (s_count + a_count + b_count). */
1610
1779
  graded_holders: number;
1611
1780
  /** Best grade present on the piled side; null when none. */
1612
- top_grade?: "S" | "A" | "B";
1781
+ top_grade: "S" | "A" | "B" | null;
1613
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). */
1614
- smart_score?: number | null;
1783
+ smart_score: number | null;
1615
1784
  /** Market volume (USD). */
1616
- volume?: number | null;
1785
+ volume: number | null;
1617
1786
  /** Aggregate recent flow direction on the market; null when unavailable. */
1618
- net_side?: "BUY" | "SELL";
1787
+ net_side: "BUY" | "SELL" | null;
1619
1788
  /** Grade-weighted pile score (5*s + 4*a + 3*b) * sharp_pct; the raw conviction input to the ranking (see directional_rank_score). */
1620
1789
  conviction_score: number;
1621
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. */
1622
- one_way_holder_count?: number | null;
1791
+ one_way_holder_count: number | null;
1623
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. */
1624
- hedged_holder_count?: number | null;
1793
+ hedged_holder_count: number | null;
1625
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. */
1626
- one_way_graded_usd?: number | null;
1795
+ one_way_graded_usd: number | null;
1627
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. */
1628
- directional_confidence?: number | null;
1797
+ directional_confidence: number | null;
1629
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. */
1630
1799
  directional_rank_score: number;
1631
1800
  category_skill: SportsEdgeSignalCategorySkill;
@@ -1683,36 +1852,36 @@ export type Trader = {
1683
1852
  /** Prefixed ID (trd_...). */
1684
1853
  id: string;
1685
1854
  address: string;
1686
- username?: string | null;
1855
+ username?: string;
1687
1856
  grade?: "S" | "A" | "B" | "C" | "D" | "F";
1688
- /** 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. */
1689
1858
  streak_tier?: "hot" | "rising" | "neutral" | "cooling" | "cold";
1690
- score?: number | null;
1691
- rank?: number | null;
1859
+ score?: number;
1860
+ rank?: number;
1692
1861
  pnl: {
1693
- total?: number | null;
1862
+ total?: number;
1694
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. */
1695
- realized?: number | null;
1696
- unrealized?: number | null;
1697
- /** 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. */
1698
- last_7d?: number | null;
1699
- /** 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. */
1700
- 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;
1701
1870
  };
1702
1871
  stats: {
1703
- markets_traded?: number | null;
1704
- win_rate?: number | null;
1705
- daily_win_rate?: number | null;
1872
+ markets_traded?: number;
1873
+ win_rate?: number;
1874
+ daily_win_rate?: number;
1706
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. */
1707
- total_volume?: number | null;
1876
+ total_volume?: number;
1708
1877
  };
1709
1878
  strategy?: {
1710
1879
  strategy_type?: string;
1711
- description?: string | null;
1712
- confidence?: number | null;
1713
- } | null;
1714
- /** 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. */
1715
- 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>;
1716
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. */
1717
1886
  quant_metrics?: {
1718
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. */
@@ -1733,17 +1902,45 @@ export type Trader = {
1733
1902
  pf_percentile: number | null;
1734
1903
  /** Cross-sectional percentile rank of edge consistency versus all traders, 0-100. null when insufficient history. */
1735
1904
  consistency_percentile: number | null;
1736
- } | null;
1737
- last_active?: string | null;
1738
- synced_at?: string | null;
1905
+ };
1906
+ last_active?: string;
1907
+ synced_at?: string;
1739
1908
  /** synced, unknown, or pending. */
1740
- sync_status?: string | null;
1909
+ sync_status?: string;
1741
1910
  /** Field-level trust metadata. Present only when expand=trust or expand[]=trust is requested. */
1742
1911
  trust?: TraderTrust;
1743
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. */
1744
1913
  category_records?: CategorySkillV2[];
1745
1914
  category_skill_model?: CategorySkillModelReadiness;
1746
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
+ };
1747
1944
  export type TraderContext = {
1748
1945
  trader: Trader;
1749
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. */
@@ -1769,9 +1966,9 @@ export type TraderContext = {
1769
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. */
1770
1967
  resolved_win_rate: number | null;
1771
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. */
1772
- resolved_wins?: number | null;
1969
+ resolved_wins: number | null;
1773
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. */
1774
- resolved_decided?: number | null;
1971
+ resolved_decided: number | null;
1775
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. */
1776
1973
  as_of: string | null;
1777
1974
  };
@@ -1780,16 +1977,30 @@ export type TraderContext = {
1780
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). */
1781
1978
  freshness_note: string;
1782
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
+ };
1783
1994
  export type TraderExportJob = {
1784
1995
  object: "trader_export_job";
1785
1996
  data: {
1786
1997
  job_id: number;
1787
1998
  status: "queued" | "running" | "ready" | "failed";
1788
1999
  format: "json" | "ndjson" | "csv";
1789
- total_trades?: number | null;
1790
- processed_trades?: number | null;
1791
- file_size?: number | null;
1792
- error?: string | null;
2000
+ total_trades: number | null;
2001
+ processed_trades: number | null;
2002
+ file_size: number | null;
2003
+ error: string | null;
1793
2004
  };
1794
2005
  meta: ResponseMeta;
1795
2006
  };
@@ -1805,26 +2016,26 @@ export type TraderExportSnapshot = {
1805
2016
  export type TraderPnl = {
1806
2017
  /** Prefixed trader ID (`trd_...`). */
1807
2018
  id: string;
1808
- /** 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`). */
1809
- 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;
1810
2021
  /** Daily cumulative-P&L series (oldest-first). */
1811
- entries: ({
2022
+ entries: {
1812
2023
  date: string;
1813
- markets_traded?: number | null;
1814
- total_volume?: number | null;
1815
- cumulative_profit?: number | null;
1816
- total_pnl?: number | null;
2024
+ markets_traded?: number;
2025
+ total_volume?: number;
2026
+ cumulative_profit?: number;
2027
+ total_pnl?: number;
1817
2028
  daily_change: number;
1818
- })[];
2029
+ }[];
1819
2030
  stats: {
1820
2031
  all: {
1821
2032
  current: number;
1822
2033
  change: number;
1823
2034
  change_pct: number;
1824
2035
  best_day: number;
1825
- best_day_date?: string | null;
2036
+ best_day_date?: string;
1826
2037
  worst_day: number;
1827
- worst_day_date?: string | null;
2038
+ worst_day_date?: string;
1828
2039
  win_days: number;
1829
2040
  loss_days: number;
1830
2041
  avg_day: number;
@@ -1835,9 +2046,9 @@ export type TraderPnl = {
1835
2046
  change: number;
1836
2047
  change_pct: number;
1837
2048
  best_day: number;
1838
- best_day_date?: string | null;
2049
+ best_day_date?: string;
1839
2050
  worst_day: number;
1840
- worst_day_date?: string | null;
2051
+ worst_day_date?: string;
1841
2052
  win_days: number;
1842
2053
  loss_days: number;
1843
2054
  avg_day: number;
@@ -1848,9 +2059,9 @@ export type TraderPnl = {
1848
2059
  change: number;
1849
2060
  change_pct: number;
1850
2061
  best_day: number;
1851
- best_day_date?: string | null;
2062
+ best_day_date?: string;
1852
2063
  worst_day: number;
1853
- worst_day_date?: string | null;
2064
+ worst_day_date?: string;
1854
2065
  win_days: number;
1855
2066
  loss_days: number;
1856
2067
  avg_day: number;
@@ -1861,9 +2072,9 @@ export type TraderPnl = {
1861
2072
  change: number;
1862
2073
  change_pct: number;
1863
2074
  best_day: number;
1864
- best_day_date?: string | null;
2075
+ best_day_date?: string;
1865
2076
  worst_day: number;
1866
- worst_day_date?: string | null;
2077
+ worst_day_date?: string;
1867
2078
  win_days: number;
1868
2079
  loss_days: number;
1869
2080
  avg_day: number;
@@ -1917,10 +2128,10 @@ export type TrendingWallet = {
1917
2128
  address: string;
1918
2129
  /** 1-based rank within the full ranked set (stable across pages). */
1919
2130
  rank: number;
1920
- username?: string | null;
2131
+ username?: string;
1921
2132
  /** Official Polymarket avatar URL (profileImage). */
1922
- profile_image_url?: string | null;
1923
- /** Real provider platform; surfaced, never coerced. Polymarket-only today. */
2133
+ profile_image_url?: string;
2134
+ /** Real provider platform; surfaced, never coerced. Polymarket only. */
1924
2135
  platform: "polymarket";
1925
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. */
1926
2137
  trending_pnl_usd: number;
@@ -1933,11 +2144,11 @@ export type TrendingWallet = {
1933
2144
  window_trade_days: number;
1934
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). */
1935
2146
  grade?: "S" | "A" | "B" | "C" | "D" | "F";
1936
- /** 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. */
1937
2148
  streak_tier?: "hot" | "rising" | "neutral" | "cooling" | "cold";
1938
- all_time_pnl_usd?: number | null;
1939
- all_time_score?: number | null;
1940
- last_synced?: string | null;
2149
+ all_time_pnl_usd?: number;
2150
+ all_time_score?: number;
2151
+ last_synced?: string;
1941
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. */
1942
2153
  daily_pnl_series: {
1943
2154
  date: string;
@@ -1947,13 +2158,13 @@ export type TrendingWallet = {
1947
2158
  /** Whether the described value or result set is complete for its stated contract. */
1948
2159
  export type TrustCompleteness = {
1949
2160
  status: "complete" | "partial" | "not_computed" | "not_applicable" | "unavailable";
1950
- detail?: string | null;
2161
+ detail?: string;
1951
2162
  };
1952
2163
  /** Freshness metadata for a trust-critical value. This is separate from transport cache fields in ResponseMeta. */
1953
2164
  export type TrustFreshness = {
1954
2165
  status: "fresh" | "refreshing" | "stale" | "not_live" | "unknown" | "unavailable";
1955
- as_of?: string | null;
1956
- max_age_s?: number | null;
2166
+ as_of?: string;
2167
+ max_age_s?: number;
1957
2168
  };
1958
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. */
1959
2170
  export type TrustMetadata = {
@@ -1965,7 +2176,7 @@ export type TrustMetadata = {
1965
2176
  /** How provider-owned facts were reconciled with stored/read-model values. */
1966
2177
  export type TrustReconciliation = {
1967
2178
  status: "provider_backed" | "db_mirror" | "computed" | "partial" | "not_applicable" | "unavailable";
1968
- detail?: string | null;
2179
+ detail?: string;
1969
2180
  };
1970
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. */
1971
2182
  export type TrustSource = {
@@ -1973,7 +2184,7 @@ export type TrustSource = {
1973
2184
  /** Provider, table/read-model, cache, or service that owns the value. */
1974
2185
  owner: string;
1975
2186
  /** Provider field, DB column, or computed field name when applicable. */
1976
- field?: string | null;
2187
+ field?: string;
1977
2188
  };
1978
2189
  export type UpdateWebhookRequest = {
1979
2190
  name?: string;
@@ -2000,6 +2211,24 @@ export type Usage = {
2000
2211
  reset_at: number;
2001
2212
  window_seconds: number;
2002
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;
2003
2232
  };
2004
2233
  meta: ResponseMeta;
2005
2234
  };
@@ -2026,6 +2255,8 @@ export type WebhookDelivery = {
2026
2255
  delivered_at?: string;
2027
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). */
2028
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;
2029
2260
  created_at: string;
2030
2261
  };
2031
2262
  export type WebhookEndpoint = {
@@ -2035,13 +2266,14 @@ export type WebhookEndpoint = {
2035
2266
  url: string;
2036
2267
  event_types: WebhookEventType[];
2037
2268
  status: WebhookStatus;
2038
- verified_at?: string | null;
2269
+ verified_at: string | null;
2039
2270
  verification_token_expires_at: string;
2040
2271
  failure_count: number;
2041
2272
  created_at: string;
2042
2273
  updated_at: string;
2043
2274
  retry_policy: WebhookRetryPolicy;
2044
- /** 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. */
2045
2277
  signing_secret?: string;
2046
2278
  verification?: WebhookVerification;
2047
2279
  };
@@ -2064,6 +2296,12 @@ export type WebhookRetryPolicy = {
2064
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. */
2065
2297
  disable_after_consecutive_failures: 8;
2066
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
+ };
2067
2305
  export type WebhookStatus = "pending_verification" | "active" | "disabled";
2068
2306
  export type WebhookVerification = {
2069
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. */
@@ -2077,44 +2315,49 @@ export type WhaleTrade = {
2077
2315
  size_usd: number;
2078
2316
  side: "BUY" | "SELL";
2079
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). */
2080
- outcome?: string | null;
2318
+ outcome: string | null;
2081
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. */
2082
- token_id?: string | null;
2320
+ token_id: string | null;
2083
2321
  price: number;
2084
- /** 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. */
2085
2323
  signal_score: number;
2086
- /** 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. */
2087
2325
  recorded_signal_score: number | null;
2088
2326
  /** Persisted live suspicion score from the scorer. Null when the row has no persisted score. */
2089
2327
  suspicion_score: number | null;
2090
2328
  /** Persisted scorer track. Null when a legacy row has no stored track label. */
2091
- suspicion_track: "whale" | "fresh_conviction" | "sliced_position";
2329
+ suspicion_track: "whale" | "fresh_conviction" | "sliced_position" | null;
2092
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. */
2093
2331
  market_volume_share?: number;
2094
2332
  trader: {
2095
2333
  id: string;
2096
2334
  address: string;
2097
- username?: string | null;
2098
- 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";
2099
2342
  };
2100
2343
  market: {
2101
2344
  id: string;
2102
2345
  condition_id: string;
2103
2346
  title: string;
2104
- slug?: string | null;
2347
+ slug?: string;
2105
2348
  /** Provider-backed market_canonical category. */
2106
- category?: string | null;
2349
+ category?: string;
2107
2350
  };
2108
2351
  };
2109
2352
  export type WhaleTradeDetail = WhaleTrade & {
2110
2353
  counterparty_analysis: CounterpartyAnalysis;
2111
2354
  };
2112
2355
  export type WhaleTradeHistoryMeta = {
2113
- /** 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. */
2114
2357
  request_id: string;
2115
2358
  cached: boolean;
2116
- /** Cache age in seconds, null if not cached. */
2117
- 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;
2118
2361
  source: {
2119
2362
  kind: "local_replay";
2120
2363
  table: "whale_alerts";
@@ -2132,6 +2375,7 @@ export type WhaleTradeHistoryMeta = {
2132
2375
  * convenience method.
2133
2376
  */
2134
2377
  export interface OperationData {
2378
+ activateWebhookSecret: WebhookEndpoint;
2135
2379
  batchGetMarketIntel: BatchMarketIntelItem[];
2136
2380
  batchGetTraders: BatchTraderItem[];
2137
2381
  createMcpJsonRpcResponse: {
@@ -2150,6 +2394,13 @@ export interface OperationData {
2150
2394
  user_id: number;
2151
2395
  credential_id: number;
2152
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
+ };
2153
2404
  /** Approved OAuth scopes; null for full developer-key access. */
2154
2405
  scopes: string[] | null;
2155
2406
  };
@@ -2161,6 +2412,8 @@ export interface OperationData {
2161
2412
  db?: boolean;
2162
2413
  cache?: boolean;
2163
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;
2164
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. */
2165
2418
  background_jobs: {
2166
2419
  status: "ok" | "degraded" | "down" | "not_checked";
@@ -2179,6 +2432,7 @@ export interface OperationData {
2179
2432
  getInsiderRadarFlag: RadarFlag;
2180
2433
  getMarketCandles: MarketCandles;
2181
2434
  getMarketContextMarkdown: string;
2435
+ getMarketHolders: MarketHolder[];
2182
2436
  getMarketIntel: MarketIntel;
2183
2437
  getMarketSnapshot: MarketSnapshot;
2184
2438
  getMonthlyReportSnapshot: ReportSnapshot;
@@ -2191,6 +2445,7 @@ export interface OperationData {
2191
2445
  getReports: ReportSnapshot;
2192
2446
  getStream: string;
2193
2447
  getTrader: Trader;
2448
+ getTraderCategoryRecords: TraderCategoryRecords;
2194
2449
  getTraderContext: TraderContext;
2195
2450
  getTraderContextMarkdown: string;
2196
2451
  getTraderExportSnapshot: TraderExportSnapshot;
@@ -2198,10 +2453,10 @@ export interface OperationData {
2198
2453
  job_id: number;
2199
2454
  status: "queued" | "running" | "ready" | "failed";
2200
2455
  format: "json" | "ndjson" | "csv";
2201
- total_trades?: number | null;
2202
- processed_trades?: number | null;
2203
- file_size?: number | null;
2204
- error?: string | null;
2456
+ total_trades: number | null;
2457
+ processed_trades: number | null;
2458
+ file_size: number | null;
2459
+ error: string | null;
2205
2460
  };
2206
2461
  getTraderPnl: TraderPnl;
2207
2462
  getUsage: {
@@ -2220,6 +2475,24 @@ export interface OperationData {
2220
2475
  reset_at: number;
2221
2476
  window_seconds: number;
2222
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;
2223
2496
  };
2224
2497
  getWebhook: WebhookEndpoint;
2225
2498
  getWeeklyReportSnapshot: ReportSnapshot;
@@ -2240,8 +2513,10 @@ export interface OperationData {
2240
2513
  listWhaleTradeCounterpartyMakers: CounterpartyMakerPage;
2241
2514
  listWhaleTradeHistory: WhaleTrade[];
2242
2515
  listWhaleTrades: WhaleTrade[];
2243
- openMcpEventStream: string;
2516
+ prepareWebhookSecret: WebhookEndpoint;
2244
2517
  redeliverWebhookDelivery: WebhookDelivery;
2518
+ registerAgent: AgentRegistration;
2519
+ retireWebhookSecret: WebhookEndpoint;
2245
2520
  rotateWebhookSecret: WebhookEndpoint;
2246
2521
  searchContent: ContentSearchResult[];
2247
2522
  searchMarkets: MarketSearchResult[];
@@ -2249,22 +2524,20 @@ export interface OperationData {
2249
2524
  job_id: number;
2250
2525
  status: "queued" | "running" | "ready" | "failed";
2251
2526
  format: "json" | "ndjson" | "csv";
2252
- total_trades?: number | null;
2253
- processed_trades?: number | null;
2254
- file_size?: number | null;
2255
- error?: string | null;
2527
+ total_trades: number | null;
2528
+ processed_trades: number | null;
2529
+ file_size: number | null;
2530
+ error: string | null;
2256
2531
  };
2257
2532
  updateWebhook: WebhookEndpoint;
2258
2533
  verifyWebhook: WebhookEndpoint;
2259
2534
  }
2260
2535
  /** Each operation's documented query parameters. */
2261
2536
  export interface OperationQuery {
2537
+ activateWebhookSecret: Record<string, never>;
2262
2538
  batchGetMarketIntel: Record<string, never>;
2263
2539
  batchGetTraders: Record<string, never>;
2264
- createMcpJsonRpcResponse: {
2265
- /** 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. */
2266
- token?: string;
2267
- };
2540
+ createMcpJsonRpcResponse: Record<string, never>;
2268
2541
  createWebhook: Record<string, never>;
2269
2542
  deleteWebhook: Record<string, never>;
2270
2543
  exploreMarkets: {
@@ -2290,22 +2563,42 @@ export interface OperationQuery {
2290
2563
  date: string;
2291
2564
  };
2292
2565
  getEventReplaySince: {
2293
- /** 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. */
2294
2567
  cursor?: string;
2295
2568
  /** Maximum durable public whale-trade events to return. */
2296
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"[];
2297
2580
  };
2298
2581
  getHealth: Record<string, never>;
2299
2582
  getInsiderRadarFlag: Record<string, never>;
2300
2583
  getMarketCandles: {
2301
2584
  /** Bucketing granularity. 1d aggregates by UTC calendar day, 1w by ISO week (Monday 00:00 UTC start). Defaults to 1d. */
2302
2585
  resolution?: "1d" | "1w";
2303
- /** 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. */
2304
2587
  from?: number;
2305
- /** 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. */
2306
2589
  to?: number;
2307
2590
  };
2308
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
+ };
2309
2602
  getMarketIntel: {
2310
2603
  /** Lookback window for whale flow aggregation. */
2311
2604
  timeframe?: "1h" | "4h" | "24h" | "7d";
@@ -2343,7 +2636,7 @@ export interface OperationQuery {
2343
2636
  getReports: {
2344
2637
  /** Report granularity selector. */
2345
2638
  granularity: "daily" | "weekly" | "monthly";
2346
- /** 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. */
2347
2640
  period: string;
2348
2641
  };
2349
2642
  getStream: {
@@ -2364,6 +2657,10 @@ export interface OperationQuery {
2364
2657
  /** Include heavy fields and trust metadata. Repeatable: strategy, categories, quant_metrics, trust. */
2365
2658
  expand?: ("strategy" | "categories" | "quant_metrics" | "trust")[];
2366
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
+ };
2367
2664
  getTraderContext: Record<string, never>;
2368
2665
  getTraderContextMarkdown: Record<string, never>;
2369
2666
  getTraderExportSnapshot: Record<string, never>;
@@ -2375,11 +2672,11 @@ export interface OperationQuery {
2375
2672
  getUsage: Record<string, never>;
2376
2673
  getWebhook: Record<string, never>;
2377
2674
  getWeeklyReportSnapshot: {
2378
- /** 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. */
2379
2676
  from?: string;
2380
- /** 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. */
2381
2678
  to?: string;
2382
- /** 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. */
2383
2680
  week?: string;
2384
2681
  };
2385
2682
  getWhaleTrade: Record<string, never>;
@@ -2392,13 +2689,15 @@ export interface OperationQuery {
2392
2689
  min_suspicion?: number;
2393
2690
  /** Compatible filter. flag selects live threshold crossings. watch returns no rows because no live watch policy exists. */
2394
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";
2395
2694
  };
2396
2695
  listLargePositions: {
2397
2696
  /** Maximum number of large positions to return. */
2398
2697
  limit?: number;
2399
2698
  /** Opaque pagination cursor from a previous response. */
2400
2699
  cursor?: string;
2401
- /** 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. */
2402
2701
  min_size?: number;
2403
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. */
2404
2703
  category?: string;
@@ -2422,10 +2721,16 @@ export interface OperationQuery {
2422
2721
  limit?: number;
2423
2722
  /** Pagination cursor from previous response's next_cursor. */
2424
2723
  cursor?: string;
2425
- /** 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. */
2426
2725
  min_size?: number;
2427
2726
  /** Exact match against provider-backed market_canonical.category. */
2428
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[];
2429
2734
  /** Minimum trader grade allowlist. `A` matches S and A; `B` matches S, A, B; etc. */
2430
2735
  min_grade?: "S" | "A" | "B" | "C" | "D" | "F";
2431
2736
  /** Filter by the binary outcome side. `yes` maps to outcome_index=0, `no` to outcome_index=1. */
@@ -2436,7 +2741,7 @@ export interface OperationQuery {
2436
2741
  timeframe?: "1h" | "4h" | "24h" | "7d";
2437
2742
  /** Page size. */
2438
2743
  limit?: number;
2439
- /** 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. */
2440
2745
  cursor?: string;
2441
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. */
2442
2747
  category?: string;
@@ -2452,7 +2757,7 @@ export interface OperationQuery {
2452
2757
  timeframe?: "1h" | "4h" | "24h" | "7d";
2453
2758
  /** Page size. */
2454
2759
  limit?: number;
2455
- /** 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. */
2456
2761
  cursor?: string;
2457
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. */
2458
2763
  category?: string;
@@ -2488,7 +2793,7 @@ export interface OperationQuery {
2488
2793
  listTrendingWallets: {
2489
2794
  /** Polymarket's weekly leaderboard caps the ranked set at 50 wallets; requests above 50 still return at most 50. */
2490
2795
  limit?: number;
2491
- /** 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. */
2492
2797
  cursor?: string;
2493
2798
  /** Trailing window. */
2494
2799
  window?: "7d" | "30d";
@@ -2496,7 +2801,7 @@ export interface OperationQuery {
2496
2801
  listWebhookDeliveries: {
2497
2802
  /** Opaque pagination cursor returned as next_cursor by a prior response. Omit to fetch the newest page. */
2498
2803
  cursor?: string;
2499
- /** Maximum delivery rows to return per page. */
2804
+ /** Maximum delivery rows to return per page. Out-of-range values are clamped to 1..100. */
2500
2805
  limit?: number;
2501
2806
  };
2502
2807
  listWebhookEvents: Record<string, never>;
@@ -2522,15 +2827,15 @@ export interface OperationQuery {
2522
2827
  limit?: number;
2523
2828
  /** Pagination cursor from previous response's next_cursor. Prefix: wth_. URL-encode when replaying as a query parameter. */
2524
2829
  cursor?: string;
2525
- /** 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. */
2526
2831
  min_size?: number;
2527
2832
  /** Exact raw provider condition_id. Unknown markets return an empty list. */
2528
2833
  condition_id?: string;
2529
- /** 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. */
2530
2835
  trader?: string;
2531
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. */
2532
2837
  category?: string;
2533
- /** 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. */
2534
2839
  min_grade?: "S" | "A" | "B" | "C" | "D" | "F";
2535
2840
  /** When true, return only rows with persisted suspicion_score >= 60. The filter is applied before SQL-backed limit + 1 pagination. */
2536
2841
  suspicious_only?: boolean;
@@ -2550,16 +2855,15 @@ export interface OperationQuery {
2550
2855
  min_size?: number;
2551
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. */
2552
2857
  category?: string;
2553
- /** Minimum trader grade. */
2858
+ /** Minimum trader grade as of today (trader.grade). A means S or A, B means S, A or B. */
2554
2859
  min_grade?: "S" | "A" | "B" | "C" | "D" | "F";
2555
2860
  /** When true, return only rows with persisted suspicion_score >= 60. The filter is applied before SQL-backed limit + 1 pagination. */
2556
2861
  suspicious_only?: boolean;
2557
2862
  };
2558
- openMcpEventStream: {
2559
- /** Legacy API-key query parameter for exact /api/v1/mcp only. Every other protected V1 route rejects it. Same contract as POST. */
2560
- token?: string;
2561
- };
2863
+ prepareWebhookSecret: Record<string, never>;
2562
2864
  redeliverWebhookDelivery: Record<string, never>;
2865
+ registerAgent: Record<string, never>;
2866
+ retireWebhookSecret: Record<string, never>;
2563
2867
  rotateWebhookSecret: Record<string, never>;
2564
2868
  searchContent: {
2565
2869
  /** Search query. Must be 1-256 characters before whitespace trimming and non-empty after trimming. */
@@ -2586,4 +2890,642 @@ export interface OperationQuery {
2586
2890
  updateWebhook: Record<string, never>;
2587
2891
  verifyWebhook: Record<string, never>;
2588
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
+ }
2589
3531
  //# sourceMappingURL=schema.d.ts.map