@0xinsider/mcp 3.10.0 → 3.12.0

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 (66) hide show
  1. package/README.md +12 -3
  2. package/dist/client.d.ts +3 -0
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +14 -1
  5. package/dist/client.js.map +1 -1
  6. package/dist/constants.d.ts +1 -1
  7. package/dist/constants.js +1 -1
  8. package/dist/product-cli/client.d.ts.map +1 -1
  9. package/dist/product-cli/client.js +10 -2
  10. package/dist/product-cli/client.js.map +1 -1
  11. package/dist/product-cli/index.d.ts.map +1 -1
  12. package/dist/product-cli/index.js +1 -0
  13. package/dist/product-cli/index.js.map +1 -1
  14. package/dist/product-cli/operations.js +3 -3
  15. package/dist/product-cli/operations.js.map +1 -1
  16. package/dist/sdk/client.d.ts +4 -1
  17. package/dist/sdk/client.d.ts.map +1 -1
  18. package/dist/sdk/client.js.map +1 -1
  19. package/dist/sdk/data-quality.d.ts +10 -5
  20. package/dist/sdk/data-quality.d.ts.map +1 -1
  21. package/dist/sdk/data-quality.js +2 -2
  22. package/dist/sdk/data-quality.js.map +1 -1
  23. package/dist/sdk/errors.d.ts +21 -9
  24. package/dist/sdk/errors.d.ts.map +1 -1
  25. package/dist/sdk/errors.js +25 -7
  26. package/dist/sdk/errors.js.map +1 -1
  27. package/dist/sdk/index.d.ts +1 -1
  28. package/dist/sdk/index.d.ts.map +1 -1
  29. package/dist/sdk/index.js.map +1 -1
  30. package/dist/sdk/schema.d.ts +856 -50
  31. package/dist/sdk/schema.d.ts.map +1 -1
  32. package/dist/sdk/stream.d.ts +18 -1
  33. package/dist/sdk/stream.d.ts.map +1 -1
  34. package/dist/sdk/stream.js +10 -1
  35. package/dist/sdk/stream.js.map +1 -1
  36. package/dist/tools/explore-markets.js +2 -2
  37. package/dist/tools/explore-markets.js.map +1 -1
  38. package/dist/tools/games.js +4 -4
  39. package/dist/tools/games.js.map +1 -1
  40. package/dist/tools/get-large-positions.js +2 -2
  41. package/dist/tools/get-large-positions.js.map +1 -1
  42. package/dist/tools/get-leaderboard.js +3 -3
  43. package/dist/tools/get-leaderboard.js.map +1 -1
  44. package/dist/tools/get-positions.js +3 -3
  45. package/dist/tools/get-positions.js.map +1 -1
  46. package/dist/tools/get-trader.d.ts.map +1 -1
  47. package/dist/tools/get-trader.js +8 -7
  48. package/dist/tools/get-trader.js.map +1 -1
  49. package/dist/tools/get-whale-trades.js +5 -5
  50. package/dist/tools/get-whale-trades.js.map +1 -1
  51. package/dist/tools/market-reads.js +2 -2
  52. package/dist/tools/market-reads.js.map +1 -1
  53. package/dist/tools/pick-of-the-day.d.ts.map +1 -1
  54. package/dist/tools/pick-of-the-day.js +80 -14
  55. package/dist/tools/pick-of-the-day.js.map +1 -1
  56. package/dist/tools/read-parity.js +18 -18
  57. package/dist/tools/read-parity.js.map +1 -1
  58. package/dist/tools/result.d.ts +6 -0
  59. package/dist/tools/result.d.ts.map +1 -1
  60. package/dist/tools/result.js +2 -0
  61. package/dist/tools/result.js.map +1 -1
  62. package/dist/tools/search-markets.js +2 -2
  63. package/dist/tools/search-markets.js.map +1 -1
  64. package/dist/tools/trader-reads.js +2 -2
  65. package/dist/tools/trader-reads.js.map +1 -1
  66. package/package.json +1 -1
@@ -51,6 +51,23 @@ export type AgentRegistration = {
51
51
  auth_guide_url: string;
52
52
  };
53
53
  };
54
+ /** A computed count with its truth state; the same envelope as AnalyticNumber. */
55
+ export type AnalyticInteger = {
56
+ state: "computed" | "known_zero" | "not_computed" | "not_applicable" | "stale" | "unavailable" | "insufficient_data";
57
+ source: "provider" | "insert_time" | "cache" | "computed";
58
+ value?: number;
59
+ freshness_at?: string;
60
+ };
61
+ /** A computed number with its truth state. value is present when state is computed or known_zero and may be present when stale; any other state says why there is no number, never a stand-in zero. */
62
+ export type AnalyticNumber = {
63
+ /** computed: a measured value. known_zero: a measured zero. stale: a value past its freshness window. not_computed: an input is unknown. not_applicable: the measure does not apply. unavailable: the source could not be read. insufficient_data: too few observations. */
64
+ state: "computed" | "known_zero" | "not_computed" | "not_applicable" | "stale" | "unavailable" | "insufficient_data";
65
+ /** Where the value came from, for diagnostics: cache is a stored aggregate, computed a request-time aggregate. Decide on state, not source. */
66
+ source: "provider" | "insert_time" | "cache" | "computed";
67
+ value?: number;
68
+ /** When the stored inputs behind the value were written or last confirmed (cache), or the request time (computed). */
69
+ freshness_at?: string;
70
+ };
54
71
  export type ApiDiscovery = {
55
72
  /** Canonical API origin for public V1 requests. */
56
73
  api_base_url: string;
@@ -77,8 +94,10 @@ export type ApiError = {
77
94
  /** 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. */
78
95
  retry_at?: string;
79
96
  freshness?: FreshnessFailure;
80
- /** 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 not on the warm sync tier (the wallets we sync most often) -- stop asking for this wallet. market_out_of_scope (404 not_found, #27303): the market or event is real and the URL is right, but 0xinsider serves sports and esports markets only -- stop asking for this market; neither a retry nor another URL for it can succeed. 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 its plan 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. cold_read_limited (429 rate_limited, #28752): the account has used its share of cold reads on GET /api/v1/market/{condition_id}/holders, requests for a market whose roster is not cached, each of which walks Polymarket (6 a minute, in bursts of up to 400); not the per-minute window, so a cached market still answers, and the next cold read is admitted at Retry-After. max_plan_required (403 forbidden, #23085): the key is valid and its account is on Pro, but the route is part of Max (GET /api/v1/edge-hunter); every Pro route keeps working with the same key, so do not disable it. The message names https://0xinsider.com/pricing, where the account upgrades; a retry never clears it. endpoint_retired (410): this legacy sports endpoint no longer serves data. Migrate to GET /api/v1/edge-hunter; retrying the retired path cannot succeed. */
81
- reason?: "cursor_expired" | "unknown_endpoint" | "pick_not_released" | "trader_not_tracked" | "market_out_of_scope" | "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" | "cold_read_limited" | "export_expired" | "freshness_ceiling_unsatisfied" | "max_plan_required" | "endpoint_retired";
97
+ /** Where a person clears this 402 (#32592): pays the overdue invoice (reason payment_overdue) or reactivates the plan (reason subscription_inactive). Present on every 402 subscription_required, omitted on every other error. The message names the same URL; link this field instead of parsing the message. */
98
+ billing_url?: string;
99
+ /** 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 not on the warm sync tier (the wallets we sync most often) -- stop asking for this wallet. market_out_of_scope (404 not_found, #27303): the market or event is real and the URL is right, but 0xinsider serves sports and esports markets only -- stop asking for this market; neither a retry nor another URL for it can succeed. 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. payment_overdue (402 subscription_required, #32592): the key is valid and the account still has its plan, but its latest subscription invoice is unpaid (Stripe past_due or unpaid), so paid access is paused; permanent until a person pays at billing_url (https://0xinsider.com/billing) -- stop retrying on a schedule and surface the link. The key works again the moment the invoice is paid. GET /api/v1/me and GET /api/v1/usage keep answering. monthly_quota_exceeded: the account has used the requests its plan 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. cold_read_limited (429 rate_limited, #28752): the account has used its share of cold reads on GET /api/v1/market/{condition_id}/holders, requests for a market whose roster is not cached, each of which walks Polymarket (6 a minute, in bursts of up to 400); not the per-minute window, so a cached market still answers, and the next cold read is admitted at Retry-After. max_plan_required (403 forbidden, #23085): the key is valid and its account is on Pro, but the route is part of Max (GET /api/v1/edge-hunter); every Pro route keeps working with the same key, so do not disable it. The message names https://0xinsider.com/pricing, where the account upgrades; a retry never clears it. endpoint_retired (410): this legacy sports endpoint no longer serves data. Migrate to GET /api/v1/edge-hunter; retrying the retired path cannot succeed. */
100
+ reason?: "cursor_expired" | "unknown_endpoint" | "pick_not_released" | "trader_not_tracked" | "market_out_of_scope" | "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" | "payment_overdue" | "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" | "cold_read_limited" | "export_expired" | "freshness_ceiling_unsatisfied" | "max_plan_required" | "endpoint_retired";
82
101
  };
83
102
  meta: ResponseMeta;
84
103
  };
@@ -91,8 +110,10 @@ export type ApiErrorBody = {
91
110
  /** 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, the recommendation is advisory and can change before a pick becomes available. Schedule the next request from the returned value instead of inferring a release schedule or polling. Prefer Retry-After for the duration because it is immune to client clock skew. */
92
111
  retry_at?: string;
93
112
  freshness?: FreshnessFailure;
94
- /** 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 not on the warm sync tier (the wallets we sync most often) -- stop asking for this wallet. market_out_of_scope (404 not_found, #27303): the market or event is real and the URL is right, but 0xinsider serves sports and esports markets only -- stop asking for this market; neither a retry nor another URL for it can succeed. 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 its plan 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. cold_read_limited (429 rate_limited, #28752): the account has used its share of cold reads on GET /api/v1/market/{condition_id}/holders, requests for a market whose roster is not cached, each of which walks Polymarket (6 a minute, in bursts of up to 400); not the per-minute window, so a cached market still answers, and the next cold read is admitted at Retry-After. max_plan_required (403 forbidden, #23085): the key is valid and its account is on Pro, but the route is part of Max (GET /api/v1/edge-hunter); every Pro route keeps working with the same key, so do not disable it. The message names https://0xinsider.com/pricing, where the account upgrades; a retry never clears it. endpoint_retired (410): this legacy sports endpoint no longer serves data. Migrate to GET /api/v1/edge-hunter; retrying the retired path cannot succeed. */
95
- reason?: "cursor_expired" | "unknown_endpoint" | "pick_not_released" | "trader_not_tracked" | "market_out_of_scope" | "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" | "cold_read_limited" | "export_expired" | "freshness_ceiling_unsatisfied" | "max_plan_required" | "endpoint_retired";
113
+ /** Where a person clears this 402 (#32592): pays the overdue invoice (reason payment_overdue) or reactivates the plan (reason subscription_inactive). Present on every 402 subscription_required, omitted on every other error. The message names the same URL; link this field instead of parsing the message. */
114
+ billing_url?: string;
115
+ /** 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 not on the warm sync tier (the wallets we sync most often) -- stop asking for this wallet. market_out_of_scope (404 not_found, #27303): the market or event is real and the URL is right, but 0xinsider serves sports and esports markets only -- stop asking for this market; neither a retry nor another URL for it can succeed. 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. payment_overdue (402 subscription_required, #32592): the key is valid and the account still has its plan, but its latest subscription invoice is unpaid (Stripe past_due or unpaid), so paid access is paused; permanent until a person pays at billing_url (https://0xinsider.com/billing) -- stop retrying on a schedule and surface the link. The key works again the moment the invoice is paid. GET /api/v1/me and GET /api/v1/usage keep answering. monthly_quota_exceeded: the account has used the requests its plan 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. cold_read_limited (429 rate_limited, #28752): the account has used its share of cold reads on GET /api/v1/market/{condition_id}/holders, requests for a market whose roster is not cached, each of which walks Polymarket (6 a minute, in bursts of up to 400); not the per-minute window, so a cached market still answers, and the next cold read is admitted at Retry-After. max_plan_required (403 forbidden, #23085): the key is valid and its account is on Pro, but the route is part of Max (GET /api/v1/edge-hunter); every Pro route keeps working with the same key, so do not disable it. The message names https://0xinsider.com/pricing, where the account upgrades; a retry never clears it. endpoint_retired (410): this legacy sports endpoint no longer serves data. Migrate to GET /api/v1/edge-hunter; retrying the retired path cannot succeed. */
116
+ reason?: "cursor_expired" | "unknown_endpoint" | "pick_not_released" | "trader_not_tracked" | "market_out_of_scope" | "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" | "payment_overdue" | "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" | "cold_read_limited" | "export_expired" | "freshness_ceiling_unsatisfied" | "max_plan_required" | "endpoint_retired";
96
117
  };
97
118
  export type BatchGameHoldersItem = {
98
119
  /** Zero-based request index. Duplicate inputs keep separate result rows. */
@@ -473,10 +494,10 @@ export type CreateWebhookVerificationAttemptRequest = {
473
494
  /** The original one-time token returned by webhook creation or a URL change. Sent only in the request body and signed receiver challenge. */
474
495
  verification_token: string;
475
496
  };
476
- /** Compact data age and coverage for a response body, always present on the operations that publish it. Read status and as_of to decide whether to use the body at all, and field_groups to see which part is weak. Everything here comes from stored observation clocks, so a cached body reports the same ages a freshly computed one does: meta.cached and meta.cache_age_s stay the only transport-time facts and neither makes this block newer. The per-field audit object is still available through expand=trust; this is the default summary of the same question. */
497
+ /** Compact data age and coverage for a response body, always present on the operations that publish it. Read status and as_of to decide whether to use the body at all, and field_groups to see which part is weak. Everything here comes from stored observation clocks, and each clocked group is judged against its writer's budget when the body is served, so a cached body reports the same ages and verdicts a freshly computed one does: meta.cached and meta.cache_age_s stay the only transport-time facts and neither makes this block newer. The per-field audit object is still available through expand=trust; this is the default summary of the same question. */
477
498
  export type DataQuality = {
478
- /** fresh when every group is fresh, unavailable when every group is unavailable, and partial in every other case. */
479
- status: "fresh" | "partial" | "unknown" | "untracked" | "unavailable";
499
+ /** fresh when every group is fresh, unavailable when every group is unavailable, stale when every group is fresh or stale and at least one is stale, and partial in every other case. */
500
+ status: "fresh" | "stale" | "partial" | "unknown" | "untracked" | "unavailable";
480
501
  /** The oldest as_of among the groups that carry one: the age of the weakest clock this body rests on. Omitted when no group carries a clock. */
481
502
  as_of?: string;
482
503
  /** One entry per field group. Entries may be added in later releases, so match on group rather than on position or length. */
@@ -488,12 +509,14 @@ export type DataQualityGroup = {
488
509
  group: string;
489
510
  /** The table and column that write this group, named so the verdict can be audited (for example trader_rankings.computed_at). */
490
511
  owner: string;
491
- /** fresh: served, and as_of carries this group's real observation or computation clock. partial: some of the group's fields are served and some are missing. unknown: served, and this read has no clock for it, so no age may be inferred. untracked: 0xinsider does not track this group for this subject, by design. unavailable: the group could not be served. New values may be added; treat one you do not recognize as unknown. fresh means the group is tracked and clocked, not that it is inside any particular tolerance: compare as_of against your own. */
492
- status: "fresh" | "partial" | "unknown" | "untracked" | "unavailable";
512
+ /** fresh: served, as_of carries this group's real observation or computation clock, and that clock is no older than max_age_s when the group carries one. stale: served and clocked, but as_of is older than max_age_s, so the writer has missed a refresh its schedule promises. partial: some of the group's fields are served and some are missing. unknown: served, and this read has no clock for it, so no age may be inferred. untracked: 0xinsider does not track this group for this subject, by design. unavailable: the group could not be served. New values may be added; treat one you do not recognize as unknown. Neither fresh nor stale is a tolerance for your use: compare as_of against your own. */
513
+ status: "fresh" | "stale" | "partial" | "unknown" | "untracked" | "unavailable";
493
514
  /** When this group's values were observed or computed. Omitted whenever the read cannot measure it, and never filled with the serialization time, the cache time, or another group's clock. */
494
515
  as_of?: string;
495
516
  /** Why the status is not fresh. Omitted when it is. */
496
517
  reason?: string;
518
+ /** The longest gap in seconds this group's writer leaves between refreshes on its schedule: the age past which the group reads stale instead of fresh. Omitted when the writer keeps no schedule its clock could fall behind (a clock stamped once, only on a change, or when a reader asks), and such a group is never stale. It is the writer's promise, not a tolerance for your use. */
519
+ max_age_s?: number;
497
520
  };
498
521
  /** The full Max-only Edge Hunter board. Defaults cover all sports and esports with B grade floor, 48-hour horizon and at most 30 rows; common selections, legacy category, min_grade and limit narrow that projection. No pagination or ETag. Rows add frozen market_context discovery metadata. */
499
522
  export type EdgeHunterBoard = {
@@ -589,7 +612,7 @@ export type EdgeHunterObservation = {
589
612
  /** Source cohort or additive projection view. emerging_pile is projected from wider_holder after source computation, overlaps its funnel denominator, and uses the source row's directional evidence. */
590
613
  cohort: "wider_holder" | "in_play" | "emerging_pile";
591
614
  /** Which evaluation place in its sport the row took this refresh. most_held: a wider_holder place for up to 8 markets per sport kicking off within 24 hours, most graded holders first, kept until kickoff while the holder page still shows a card or could not be read; also every in_play row, whose places go most graded holders first. soonest_kickoff: a wider_holder place among the sport's 8 soonest kickoffs, which is not kept. emerging_pile rows carry their source wider_holder row's value. Filter on most_held to keep the most-held selection. most_held_48h: every row of an admission=most_held_48h response, which is that opt-in selection (up to 8 markets per sport within 48 hours, most graded holders first, recomputed every refresh), including a market a default place also evaluates; it never appears on a default response. */
592
- admitted_by: "most_held" | "soonest_kickoff" | "most_held_48h";
615
+ admitted_by: "most_held" | "soonest_kickoff" | "most_held_48h" | "most_held_48h_by_type";
593
616
  /** Always true. This row must not be routed to an order executor. */
594
617
  observation_only: true;
595
618
  /**
@@ -672,7 +695,7 @@ export type EdgeHunterObservationDeparture = {
672
695
  /** Canonical sport bucket the departed card carried. */
673
696
  category: "Basketball" | "Football" | "Baseball" | "Hockey" | "MMA" | "Boxing" | "Soccer" | "Cricket" | "Golf" | "Tennis" | "Esports" | "Racing" | "Table Tennis" | "Pickleball";
674
697
  /** The departed card's admitted_by: most_held_48h on an admission=most_held_48h response. */
675
- admitted_by: "most_held" | "soonest_kickoff" | "most_held_48h";
698
+ admitted_by: "most_held" | "soonest_kickoff" | "most_held_48h" | "most_held_48h_by_type";
676
699
  /** Kickoff the departed card carried, in UTC. The entry leaves the list once it passes. */
677
700
  game_start_time: string;
678
701
  /** The departed card's observed_at: when its last evaluation finished. */
@@ -702,7 +725,7 @@ export type EdgeHunterObservationsResponse = {
702
725
  /** Normalized axes requested with a selector or category; omitted on an unselected default read. */
703
726
  selection?: EdgeHunterSelection;
704
727
  /** Echoes the opt-in admission rule a request named; omitted on a default read. When present, data, funnel, coverage, degraded and degradation_reasons describe that selection, not the default one. */
705
- admission?: "most_held_48h";
728
+ admission?: "most_held_48h" | "most_held_48h_by_type";
706
729
  /** cohort=wider_holder only, for the default selection and for admission=most_held_48h: markets that had a wider_holder card in an earlier snapshot of the same selection, have none in this one, and have not kicked off. Newest departed_at first. An entry stays until the game_start_time it carries passes, and leaves as soon as the market has a card again; while it stays, its reason changes only while it reports an unfinished read or when view=signals starts or stops listing the market (see reason), and a later departure of the same market is a new entry. Filtered by the same category and selectors as data, and identical on every page of one snapshot. At most 336 entries; when more are open, the oldest departures leave first. An empty array means no card of this selection is departed. Omitted on in_play and emerging_pile, and on a snapshot that could not establish its departures, never reported as an empty array. Tracking that restarts after its record is lost starts empty. */
707
730
  departures?: EdgeHunterObservationDeparture[];
708
731
  /** The ranked_at of the view=signals snapshot whose listed markets this snapshot excluded from wider_holder as primary_slate_candidate. The refresh that computed this snapshot read it as it started, so it can be one refresh older than the view=signals snapshot a reader sees at the same moment. null when no view=signals snapshot could be read: that refresh excluded no market, and the funnel counts no primary_slate_candidate. Omitted on an unmappable legacy category, which reads no generation. */
@@ -1233,8 +1256,8 @@ export type FreshnessFailure = {
1233
1256
  actual_age_s?: number;
1234
1257
  /** The oldest stored data-quality clock used to calculate actual_age_s, when one is available. */
1235
1258
  as_of?: string;
1236
- /** The trader body's whole-response data-quality status. Only fresh can satisfy max_age_s. */
1237
- data_quality_status: "fresh" | "partial" | "unknown" | "untracked" | "unavailable";
1259
+ /** The trader body's whole-response data-quality status. Only fresh or stale can satisfy max_age_s: the ceiling replaces each writer's own budget, so a stale body inside it is answered. */
1260
+ data_quality_status: "fresh" | "stale" | "partial" | "unknown" | "untracked" | "unavailable";
1238
1261
  };
1239
1262
  /** One sports or esports game: both sides, its schedule, provider status, its winner markets (the moneyline, or the soccer 1X2 legs) with their available provider moneyline price states and liquidity, and the game's traded volume. The event's other markets are on GET /api/v1/games/{event_slug}/markets. Assembled from the same provider-first live and upcoming projections the site's boards use, with no request-time provider fan-out. */
1240
1263
  export type Game = {
@@ -1267,6 +1290,8 @@ export type Game = {
1267
1290
  sharp_money?: GameSharpMoney;
1268
1291
  /** The game's traded volume, the figure the sports board carries for it, with its source, basis, unit and observation clock. A client can rank or filter games by volume.value. Omitted when the board carries no volume for the game, and on a finished game read from its stored record (freshness.source stored); never 0 in place of a missing figure. */
1269
1292
  volume?: GameVolume;
1293
+ /** A tennis game's tournament edition: its tier, city and country, venue time zone and official dates, from 0xinsider's reviewed registry, the same facts the game's page states. Omitted outside tennis, on a finished game read from its stored record (freshness.source stored), and when the registry holds no single edition for the game's competition label, players' tour and kickoff; never a guessed value. */
1294
+ tournament?: GameTournament;
1270
1295
  };
1271
1296
  /** One side of the game. */
1272
1297
  export type GameCompetitor = {
@@ -1322,10 +1347,12 @@ export type GameHoldersItem = {
1322
1347
  market: MarketHoldersMarket;
1323
1348
  scan: MarketHoldersScan;
1324
1349
  totals: MarketHoldersTotals;
1325
- /** When this roster was computed. A cached roster is at most 60 seconds old. */
1350
+ /** When this roster was computed. A fresh cached roster is at most 60 seconds old; a stale one at most 15 minutes. */
1326
1351
  computed_at: string;
1327
- /** true when the roster came from the 60-second roster cache. */
1352
+ /** true when the roster came from the cache. */
1328
1353
  cached: boolean;
1354
+ /** true when the market had no fresh roster at the batch deadline and this is the last roster published for it, up to 15 minutes old (read computed_at). The fresh one is still computing, so a read a few seconds later normally gets it; a market refused over the account's cold-read share is served the same way. */
1355
+ stale: boolean;
1329
1356
  };
1330
1357
  /** One Polymarket market linked to this game. */
1331
1358
  export type GameMarket = {
@@ -1490,6 +1517,38 @@ export type GameStatus = {
1490
1517
  /** Whether the game is over. Always present. */
1491
1518
  ended: boolean;
1492
1519
  };
1520
+ /** The tennis tournament edition a game belongs to, curated from official ATP, WTA and ITF pages (source_urls), never from Polymarket, which supplies the competition label and tour only. Selected by the game's provider competition label, the one tour both players carry, and the kickoff's day at the venue. A fact no official page states is omitted. */
1521
+ export type GameTournament = {
1522
+ /** The provider competition label that selected this edition, verbatim, for example "Erste Bank Open, Qualification". */
1523
+ label: string;
1524
+ /** The edition's tour. */
1525
+ tour: "atp" | "wta" | "itf";
1526
+ /** The match's draw. qualification when the provider competition label carries Polymarket's qualifying mark (", Qualification", which 0xinsider also applies when Polymarket flags an ATP Challenger qualifying fixture); main for an unmarked ATP or WTA label. Omitted for an unmarked ITF label: Polymarket gives an ITF qualifying match the main draw's label. */
1527
+ draw?: "main" | "qualification";
1528
+ /** The edition's verified category, for example "ATP Masters 1000", "ATP Challenger 50", "WTA 1000" or "ITF M25". Omitted when no official page states it. */
1529
+ tier?: string;
1530
+ /** The verified venue city and country. Omitted when no official page states it. */
1531
+ location?: GameTournamentLocation;
1532
+ /** The venue's IANA time zone, for example "Europe/Rome". Format the venue's local time with it; it carries the daylight-saving rules. Omitted when the venue is unverified. */
1533
+ timezone?: string;
1534
+ /** The year of the edition. */
1535
+ edition_year: number;
1536
+ /** The edition's first official day, inclusive (YYYY-MM-DD). A qualifying match can be played up to two days before it. */
1537
+ starts_on: string;
1538
+ /** The edition's last official day, inclusive (YYYY-MM-DD). */
1539
+ ends_on: string;
1540
+ /** The official tournament, tour, federation or time-zone pages the facts were taken from. */
1541
+ source_urls: string[];
1542
+ /** When those pages were checked: a catalogue verification date, not a score or price clock. */
1543
+ checked_on: string;
1544
+ };
1545
+ /** A verified tournament venue. */
1546
+ export type GameTournamentLocation = {
1547
+ city: string;
1548
+ country: string;
1549
+ /** ISO 3166-1 alpha-2, for example "IT". */
1550
+ country_code: string;
1551
+ };
1493
1552
  /** One fill in a game, as the game page's activity list shows it. */
1494
1553
  export type GameTrade = {
1495
1554
  /** Stable fill identity: {transaction_hash}:{token_id}:{wallet}:{shares}. Deduplicate on it across polls. */
@@ -1855,6 +1914,21 @@ export type LeaderboardPriceEdge = {
1855
1914
  /** Why the leaderboard does not rank a ranked edge. record_incomplete: the wallet's stored sports and esports record shows more profit than Polymarket reports for it, so some losing markets are likely missing. Omitted when nothing holds the edge, and always omitted unless status is ranked. */
1856
1915
  hold?: "record_incomplete";
1857
1916
  };
1917
+ /** The whole board's totals, the counts the 0xinsider leaderboard page shows (#32737), read with the ranking snapshot the page is served at. Sent on every page of a request with no category and no strategy, whatever its sort, dir and activity, which order or split the same wallets. Omitted on a category or strategy page, which lists a subset these totals do not describe, and while the ranking has no totals for the served generation. */
1918
+ export type LeaderboardSummary = {
1919
+ /** Ranked wallets on the board: the wallets the unfiltered list pages through. */
1920
+ ranked_total: number;
1921
+ /** Ranked wallets by grade. Every ranked wallet is graded S, A or B, so the three sum to ranked_total. */
1922
+ by_grade: {
1923
+ S: number;
1924
+ A: number;
1925
+ B: number;
1926
+ };
1927
+ /** Ranked wallets whose last trade was 30 days or less before as_of: the wallets activity=active lists. ranked_total minus active_30d is the activity=inactive count. */
1928
+ active_30d: number;
1929
+ /** When the totals were counted, UTC. They are recounted about once a minute while the ranking is current. */
1930
+ as_of: string;
1931
+ };
1858
1932
  /** One side's score line inside a `live_sports_updated` pulse. */
1859
1933
  export type LiveSportsScoreEntry = {
1860
1934
  /** Team name, ordered for the league (away first where the league reads that way). */
@@ -2013,8 +2087,8 @@ export type MarketHolder = {
2013
2087
  category_avg_price?: number;
2014
2088
  /** Where `category_win_rate` and `category_win_record` were measured: for an esports market the 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`), and for a market in a registered league that league, by the name Pick of the Day uses for it (`NBA`, `NFL`, `NHL`, `MLB`, `UFC`, `ATP`, `WTA`, `LaLiga`, `Premier League`, `Serie A`, `UEFA Champions League`, `MLS` and the other registered leagues). Present only when the wallet's record there clears the 5-settled-market floor, in which case the rate and record are the game's or league's rather than the whole `category` bucket's. Absent when the rate is the bucket's (the wallet's history there is under the floor, or the competition is not a registered league), on every other market, and beside every non-measured status. Label the rate with this when present and with the market's `category` otherwise. */
2015
2089
  category_win_rate_game?: string;
2016
- /** 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. */
2017
- category_win_rate_status: "measured" | "not_enough_data" | "unavailable";
2090
+ /** 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). Never `untracked`: this route lists S, A and B wallets only, all on file. Always present on this route. */
2091
+ category_win_rate_status: "measured" | "not_enough_data" | "unavailable" | "untracked";
2018
2092
  category_evidence?: HolderCategoryEvidence;
2019
2093
  /** Whole days since this wallet's first trade, rounded down (3.6 days reads 3), so it changes once a day, not on every request. The five badge fields are present together, only for a wallet that draws at least one badge. */
2020
2094
  wallet_age_days?: number | null;
@@ -2238,8 +2312,8 @@ export type MarketTopHolder = {
2238
2312
  category_avg_price?: number;
2239
2313
  /** Where `category_win_rate` and `category_win_record` were measured: for an esports market the 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`), and for a market in a registered league that league, by the name Pick of the Day uses for it (`NBA`, `NFL`, `NHL`, `MLB`, `UFC`, `ATP`, `WTA`, `LaLiga`, `Premier League`, `Serie A`, `UEFA Champions League`, `MLS` and the other registered leagues). Present only when the wallet's record there clears the 5-settled-market floor, in which case the rate and record are the game's or league's rather than the whole `category` bucket's. Absent when the rate is the bucket's (the wallet's history there is under the floor, or the competition is not a registered league), on every other market, and beside every non-measured status. Label the rate with this when present and with the market's `category` otherwise. */
2240
2314
  category_win_rate_game?: string;
2241
- /** 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 read failed; retry later). Absent when the market has no canonical category. */
2242
- category_win_rate_status?: "measured" | "not_enough_data" | "unavailable";
2315
+ /** Why `category_win_rate` is present or absent: `measured` (rate present), `not_enough_data` (the wallet is on file and under the floor of 5 decided markets in the category), `untracked` (0xinsider has no record of the wallet, so nothing was measured; `grade`, `in_scope_realized_pnl` and `in_scope_volume` are null too), or `unavailable` (a read failed; retry later). Absent when the market has no canonical category. */
2316
+ category_win_rate_status?: "measured" | "not_enough_data" | "unavailable" | "untracked";
2243
2317
  /** Whole days since this wallet's first trade, rounded down (3.6 days reads 3), so it changes once a day, not on every request. The five badge fields are present together, only for a wallet that draws at least one badge. */
2244
2318
  wallet_age_days?: number | null;
2245
2319
  /** True when the wallet's first trade was under 30 days ago. */
@@ -2266,6 +2340,8 @@ export type MarketTopHolders = {
2266
2340
  computed_at?: string;
2267
2341
  /** When Polymarket's holder board behind this sample was fetched: up to 120 s before `computed_at` on an open market. Absent on a resolved market, whose sample reads no live board, and when the fetch stamp could not be read. */
2268
2342
  positions_as_of?: string;
2343
+ /** `true` when this is the market's last sample, served after its 30 s window while a refresh runs; `positions_as_of` is then at most 300 s old. Read again in a few seconds for the refreshed sample. Always `false` on a resolved market. */
2344
+ source_stale: boolean;
2269
2345
  };
2270
2346
  export type MarketTopHoldersTotals = {
2271
2347
  /** Holders in the YES sample, before `limit`. Equal to `sample_cap` means that many or more. */
@@ -2374,8 +2450,8 @@ export type PickHolder = {
2374
2450
  category_avg_price?: number;
2375
2451
  /** Where `category_win_rate` and `category_win_record` were measured, by the same name the pick's `display_category` uses for it: for an esports pick the 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`), and for a pick in a registered league that league (`NBA`, `NFL`, `NHL`, `MLB`, `UFC`, `ATP`, `WTA`, `LaLiga`, `Premier League`, `Serie A`, `UEFA Champions League`, `MLS` and the other registered leagues). Present only when the wallet's record there clears the 5-settled-market floor, in which case the rate and record are the game's or league's rather than the whole `category` bucket's. Absent when the rate is the bucket's (the wallet's history there is under the floor, or the competition is not a registered league), on every other pick, beside every non-measured status, and on payloads predating the field. Label the rate with this when present and with `category` otherwise. */
2376
2452
  category_win_rate_game?: string;
2377
- /** Why `category_win_rate` is present or absent on a `display_holders` entry: `measured` (rate present), `not_enough_data` (the wallet is below the settled-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. */
2378
- category_win_rate_status?: "measured" | "not_enough_data" | "unavailable";
2453
+ /** Why `category_win_rate` is present or absent on a `display_holders` entry: `measured` (rate present), `not_enough_data` (the wallet is below the settled-market floor of 5 in the category), or `unavailable` (the annotation read failed; retry later). Never `untracked`: every recorded holder is a graded wallet 0xinsider has on file. Absent entirely on `holders` entries, legacy rows, and payloads predating the field -- absence means the roster was never annotated, not a small sample. */
2454
+ category_win_rate_status?: "measured" | "not_enough_data" | "unavailable" | "untracked";
2379
2455
  /** Whole days since this wallet's first trade, rounded down (3.6 days reads 3), so it changes once a day, not on every request, and the pick's ETag holds between requests. 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. */
2380
2456
  wallet_age_days?: number | null;
2381
2457
  /** True when the wallet's first trade was under 30 days ago. 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. */
@@ -2588,6 +2664,13 @@ export type PickOfTheDayArchive = {
2588
2664
  /** One entry per product day that has a published pick included in the archive, newest first, in the same order as picks. Each carries that day's net units, accumulated in the same backend pass and behind the same visibility gate as hit_rate.unit_score, so both cover the same population of picks. Re-adding the day totals reproduces hit_rate.unit_score to display precision rather than bit-for-bit, since that re-associates the floating-point sum. */
2589
2665
  days: PickOfTheDayArchiveDay[];
2590
2666
  hit_rate: PickOfTheDayHitRate;
2667
+ page?: {
2668
+ has_more: boolean;
2669
+ limit: number;
2670
+ next_cursor: string | null;
2671
+ returned: number;
2672
+ total: number;
2673
+ };
2591
2674
  };
2592
2675
  export type PickOfTheDayArchiveDay = {
2593
2676
  /** The product day (YYYY-MM-DD). */
@@ -2683,6 +2766,67 @@ export type PickOfTheDayArchiveEntry = {
2683
2766
  */
2684
2767
  supersedes_pick_id: string | null;
2685
2768
  };
2769
+ /** The archive with `view=summary`: `hit_rate` without its daily `series`, one short row per pick, and `page`. Page with `limit` and `cursor`; `view=full` returns every field of a row. */
2770
+ export type PickOfTheDayArchiveSummary = {
2771
+ hit_rate: {
2772
+ clv_applicable: number;
2773
+ clv_avg_display?: string;
2774
+ clv_avg_pct?: number;
2775
+ clv_avg_pp?: number;
2776
+ clv_avg_pp_display?: string;
2777
+ clv_beats_close: number;
2778
+ clv_coverage_display?: string;
2779
+ clv_coverage_explanation?: string;
2780
+ clv_coverage_pct?: number;
2781
+ clv_eligible: number;
2782
+ clv_measured: number;
2783
+ clv_not_applicable: number;
2784
+ clv_pending: number;
2785
+ clv_state: string;
2786
+ clv_ties: number;
2787
+ clv_total: number;
2788
+ clv_unavailable: number;
2789
+ decided: number;
2790
+ losses: number;
2791
+ net_profit_display: string;
2792
+ net_profit_usd: number;
2793
+ pct: number;
2794
+ pending: number;
2795
+ roi_display: string;
2796
+ roi_pct: number;
2797
+ stake_usd: number;
2798
+ staked_usd: number;
2799
+ unit_score?: number;
2800
+ unit_score_display?: string;
2801
+ void: number;
2802
+ win_rate_display: string;
2803
+ wins: number;
2804
+ };
2805
+ page: {
2806
+ has_more: boolean;
2807
+ limit: number;
2808
+ next_cursor: string | null;
2809
+ returned: number;
2810
+ total: number;
2811
+ };
2812
+ picks: {
2813
+ backed_price?: number;
2814
+ backed_side_locked?: boolean;
2815
+ clv_pct?: number;
2816
+ display_category?: string;
2817
+ is_free_selection: boolean;
2818
+ matchup?: string;
2819
+ outcome: string;
2820
+ pick_date: string;
2821
+ pick_id: string;
2822
+ pick_outcome_label?: string;
2823
+ publication_order: number;
2824
+ required_tier?: string;
2825
+ top_grade?: string;
2826
+ unit_score?: number;
2827
+ }[];
2828
+ view: string;
2829
+ };
2686
2830
  /** Select using the entry commitment_version, never implicit payload shape. All historic v1 hashes remain unchanged. */
2687
2831
  export type PickOfTheDayCommitmentPayload = PickOfTheDayCommitmentPayloadV1 | PickOfTheDayCommitmentPayloadV2;
2688
2832
  /** The frozen identity of the pick, exactly as the hash was taken over it. Served byte for byte as it was hashed -- keys sorted by UTF-8 byte value, no insignificant whitespace -- so a verifier concatenates and hashes with nothing to reconstruct. Property order below is the wire order. The outcome is deliberately NOT part of it: surviving a corrected outcome unchanged is the case the commitment exists for. Worked example: {"backed_price":"0.545000","condition_id":"0xabc","kickoff":"2026-09-20T23:05:00Z","pick_date":"2026-09-20","pick_outcome_index":1,"pick_outcome_label":"Lakers","pick_rank":1,"platform":"polymarket"} with the nonce 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f hashes to 44d18fa5e2aa3a2bf3c971dcc9317c8ccbdfd5480a4773b6d8ffd5fbeeea84dc. */
@@ -3355,6 +3499,446 @@ export type PickOfTheDayStats = {
3355
3499
  pick_rank: number;
3356
3500
  }[];
3357
3501
  };
3502
+ /** The stats with `view=summary` or `sections`: only the named sections, listed in `sections`. `view=summary` names every section except `series`, `days`, `categories`, `months` and `voids`. */
3503
+ export type PickOfTheDayStatsSections = {
3504
+ categories?: {
3505
+ canonical_category?: string;
3506
+ clv_avg_display?: string;
3507
+ clv_avg_pct?: number;
3508
+ clv_avg_pp?: number;
3509
+ clv_avg_pp_display?: string;
3510
+ clv_measured: number;
3511
+ edge_display?: string;
3512
+ edge_pp?: number;
3513
+ key: string;
3514
+ label: string;
3515
+ losses: number;
3516
+ net_profit_display?: string;
3517
+ net_profit_usd?: number;
3518
+ pending: number;
3519
+ picks: number;
3520
+ priced_decided: number;
3521
+ priced_in_display?: string;
3522
+ priced_in_pct?: number;
3523
+ roi_display?: string;
3524
+ roi_pct?: number;
3525
+ settled: number;
3526
+ small_sample: boolean;
3527
+ staked_usd: number;
3528
+ unit_score?: number;
3529
+ unit_score_display?: string;
3530
+ void: number;
3531
+ win_rate_display?: string;
3532
+ win_rate_pct?: number;
3533
+ wins: number;
3534
+ }[];
3535
+ days?: ({
3536
+ date: string;
3537
+ losses: number;
3538
+ net_profit_display?: string;
3539
+ net_profit_usd?: number;
3540
+ pending: number;
3541
+ picks: number;
3542
+ sweep?: "win" | "loss";
3543
+ unit_score?: number;
3544
+ unit_score_display?: string;
3545
+ void: number;
3546
+ wins: number;
3547
+ })[];
3548
+ hit_rate?: {
3549
+ clv_applicable: number;
3550
+ clv_avg_display?: string;
3551
+ clv_avg_pct?: number;
3552
+ clv_avg_pp?: number;
3553
+ clv_avg_pp_display?: string;
3554
+ clv_beats_close: number;
3555
+ clv_coverage_display?: string;
3556
+ clv_coverage_explanation?: string;
3557
+ clv_coverage_pct?: number;
3558
+ clv_eligible: number;
3559
+ clv_measured: number;
3560
+ clv_not_applicable: number;
3561
+ clv_pending: number;
3562
+ clv_state: string;
3563
+ clv_ties: number;
3564
+ clv_total: number;
3565
+ clv_unavailable: number;
3566
+ decided: number;
3567
+ losses: number;
3568
+ net_profit_display: string;
3569
+ net_profit_usd: number;
3570
+ pct: number;
3571
+ pending: number;
3572
+ roi_display: string;
3573
+ roi_pct: number;
3574
+ stake_usd: number;
3575
+ staked_usd: number;
3576
+ unit_score?: number;
3577
+ unit_score_display?: string;
3578
+ void: number;
3579
+ win_rate_display: string;
3580
+ wins: number;
3581
+ };
3582
+ market_expectations?: {
3583
+ as_of_date: string;
3584
+ price_basis: string;
3585
+ timezone: string;
3586
+ windows: ({
3587
+ clv_avg_display: string | null;
3588
+ clv_avg_pct: number | null;
3589
+ clv_avg_pp: number | null;
3590
+ clv_avg_pp_display: string | null;
3591
+ clv_measured: number;
3592
+ clv_missing: number;
3593
+ expected_wins: number | null;
3594
+ expected_wins_display: string | null;
3595
+ from_date: string | null;
3596
+ key: string;
3597
+ label: string;
3598
+ numeric_unavailable: boolean;
3599
+ priced_decided: number;
3600
+ through_date: string;
3601
+ units: number | null;
3602
+ units_display: string | null;
3603
+ units_z: number | null;
3604
+ units_z_display: string | null;
3605
+ unpriced_decided: number;
3606
+ wins: number;
3607
+ wins_z: number | null;
3608
+ wins_z_display: string | null;
3609
+ })[];
3610
+ };
3611
+ market_types?: {
3612
+ canonical_category?: string;
3613
+ clv_avg_display?: string;
3614
+ clv_avg_pct?: number;
3615
+ clv_avg_pp?: number;
3616
+ clv_avg_pp_display?: string;
3617
+ clv_measured: number;
3618
+ edge_display?: string;
3619
+ edge_pp?: number;
3620
+ key: string;
3621
+ label: string;
3622
+ losses: number;
3623
+ net_profit_display?: string;
3624
+ net_profit_usd?: number;
3625
+ pending: number;
3626
+ picks: number;
3627
+ priced_decided: number;
3628
+ priced_in_display?: string;
3629
+ priced_in_pct?: number;
3630
+ roi_display?: string;
3631
+ roi_pct?: number;
3632
+ settled: number;
3633
+ small_sample: boolean;
3634
+ staked_usd: number;
3635
+ unit_score?: number;
3636
+ unit_score_display?: string;
3637
+ void: number;
3638
+ win_rate_display?: string;
3639
+ win_rate_pct?: number;
3640
+ wins: number;
3641
+ }[];
3642
+ months?: {
3643
+ canonical_category?: string;
3644
+ clv_avg_display?: string;
3645
+ clv_avg_pct?: number;
3646
+ clv_avg_pp?: number;
3647
+ clv_avg_pp_display?: string;
3648
+ clv_measured: number;
3649
+ edge_display?: string;
3650
+ edge_pp?: number;
3651
+ key: string;
3652
+ label: string;
3653
+ losses: number;
3654
+ net_profit_display?: string;
3655
+ net_profit_usd?: number;
3656
+ pending: number;
3657
+ picks: number;
3658
+ priced_decided: number;
3659
+ priced_in_display?: string;
3660
+ priced_in_pct?: number;
3661
+ roi_display?: string;
3662
+ roi_pct?: number;
3663
+ settled: number;
3664
+ small_sample: boolean;
3665
+ staked_usd: number;
3666
+ unit_score?: number;
3667
+ unit_score_display?: string;
3668
+ void: number;
3669
+ win_rate_display?: string;
3670
+ win_rate_pct?: number;
3671
+ wins: number;
3672
+ }[];
3673
+ outcome_stats?: {
3674
+ concentration: {
3675
+ positive_wins: number;
3676
+ remaining_valued_decided: number;
3677
+ removed_wins: number;
3678
+ roi_without_top_wins_display: string | null;
3679
+ roi_without_top_wins_pct: number | null;
3680
+ target_wins: number;
3681
+ top_wins_share_display: string | null;
3682
+ top_wins_share_pct: number | null;
3683
+ valued_decided: number;
3684
+ };
3685
+ drawdown: {
3686
+ completed_days: number;
3687
+ current_days_below_peak: number | null;
3688
+ current_drawdown_display: string | null;
3689
+ current_drawdown_units: number | null;
3690
+ days_below_peak: number | null;
3691
+ excluded_days: number;
3692
+ from_date: string | null;
3693
+ longest_days_below_peak: number | null;
3694
+ longest_recovery_days: number | null;
3695
+ max_drawdown_display: string | null;
3696
+ max_drawdown_units: number | null;
3697
+ peak_date: string | null;
3698
+ peak_net_profit_usd: number | null;
3699
+ through_date: string | null;
3700
+ };
3701
+ profit_factor: {
3702
+ display: string | null;
3703
+ gross_loss_usd: number | null;
3704
+ gross_profit_usd: number | null;
3705
+ state: "empty" | "measured" | "no_losses" | "numeric_unavailable";
3706
+ value: number | null;
3707
+ valued_decided: number;
3708
+ };
3709
+ rolling: ({
3710
+ from_date: string | null;
3711
+ losses: number;
3712
+ roi_display: string | null;
3713
+ roi_pct: number | null;
3714
+ through_date: string | null;
3715
+ units: number | null;
3716
+ units_display: string | null;
3717
+ valued_decided: number;
3718
+ win_rate_display: string | null;
3719
+ win_rate_pct: number | null;
3720
+ window_size: number;
3721
+ wins: number;
3722
+ })[];
3723
+ };
3724
+ price_bands?: {
3725
+ canonical_category?: string;
3726
+ clv_avg_display?: string;
3727
+ clv_avg_pct?: number;
3728
+ clv_avg_pp?: number;
3729
+ clv_avg_pp_display?: string;
3730
+ clv_measured: number;
3731
+ edge_display?: string;
3732
+ edge_pp?: number;
3733
+ key: string;
3734
+ label: string;
3735
+ losses: number;
3736
+ net_profit_display?: string;
3737
+ net_profit_usd?: number;
3738
+ pending: number;
3739
+ picks: number;
3740
+ priced_decided: number;
3741
+ priced_in_display?: string;
3742
+ priced_in_pct?: number;
3743
+ roi_display?: string;
3744
+ roi_pct?: number;
3745
+ settled: number;
3746
+ small_sample: boolean;
3747
+ staked_usd: number;
3748
+ unit_score?: number;
3749
+ unit_score_display?: string;
3750
+ void: number;
3751
+ win_rate_display?: string;
3752
+ win_rate_pct?: number;
3753
+ wins: number;
3754
+ }[];
3755
+ records?: {
3756
+ best_day?: {
3757
+ date: string;
3758
+ date_display: string;
3759
+ losses: number;
3760
+ net_profit_display: string;
3761
+ net_profit_usd: number;
3762
+ picks: number;
3763
+ wins: number;
3764
+ };
3765
+ biggest_win?: {
3766
+ category: string;
3767
+ date: string;
3768
+ date_display: string;
3769
+ matchup: string;
3770
+ net_profit_display: string;
3771
+ net_profit_usd: number;
3772
+ };
3773
+ longest_losing_day_streak?: {
3774
+ days: number;
3775
+ end_date: string;
3776
+ net_profit_display: string;
3777
+ net_profit_usd: number;
3778
+ range_display: string;
3779
+ start_date: string;
3780
+ };
3781
+ longest_winning_day_streak?: {
3782
+ days: number;
3783
+ end_date: string;
3784
+ net_profit_display: string;
3785
+ net_profit_usd: number;
3786
+ range_display: string;
3787
+ start_date: string;
3788
+ };
3789
+ sweeps: {
3790
+ clean_sweeps: number;
3791
+ latest_clean_sweep?: {
3792
+ date: string;
3793
+ date_display: string;
3794
+ losses: number;
3795
+ wins: number;
3796
+ };
3797
+ latest_wipeout?: {
3798
+ date: string;
3799
+ date_display: string;
3800
+ losses: number;
3801
+ wins: number;
3802
+ };
3803
+ min_decided: number;
3804
+ wipeouts: number;
3805
+ };
3806
+ winning_days?: {
3807
+ flat: number;
3808
+ losing: number;
3809
+ settled: number;
3810
+ winning: number;
3811
+ winning_pct: number;
3812
+ winning_pct_display: string;
3813
+ };
3814
+ worst_day?: {
3815
+ date: string;
3816
+ date_display: string;
3817
+ losses: number;
3818
+ net_profit_display: string;
3819
+ net_profit_usd: number;
3820
+ picks: number;
3821
+ wins: number;
3822
+ };
3823
+ };
3824
+ sections: string[];
3825
+ series?: {
3826
+ date: string;
3827
+ hit_rate_pct: number;
3828
+ net_profit_usd: number;
3829
+ }[];
3830
+ sports?: {
3831
+ canonical_category?: string;
3832
+ clv_avg_display?: string;
3833
+ clv_avg_pct?: number;
3834
+ clv_avg_pp?: number;
3835
+ clv_avg_pp_display?: string;
3836
+ clv_measured: number;
3837
+ edge_display?: string;
3838
+ edge_pp?: number;
3839
+ key: string;
3840
+ label: string;
3841
+ losses: number;
3842
+ net_profit_display?: string;
3843
+ net_profit_usd?: number;
3844
+ pending: number;
3845
+ picks: number;
3846
+ priced_decided: number;
3847
+ priced_in_display?: string;
3848
+ priced_in_pct?: number;
3849
+ roi_display?: string;
3850
+ roi_pct?: number;
3851
+ settled: number;
3852
+ small_sample: boolean;
3853
+ staked_usd: number;
3854
+ unit_score?: number;
3855
+ unit_score_display?: string;
3856
+ void: number;
3857
+ win_rate_display?: string;
3858
+ win_rate_pct?: number;
3859
+ wins: number;
3860
+ }[];
3861
+ streaks?: {
3862
+ current?: number;
3863
+ current_day?: number;
3864
+ current_day_display?: string;
3865
+ current_display?: string;
3866
+ longest_loss: number;
3867
+ longest_win: number;
3868
+ };
3869
+ tiers?: {
3870
+ canonical_category?: string;
3871
+ clv_avg_display?: string;
3872
+ clv_avg_pct?: number;
3873
+ clv_avg_pp?: number;
3874
+ clv_avg_pp_display?: string;
3875
+ clv_measured: number;
3876
+ edge_display?: string;
3877
+ edge_pp?: number;
3878
+ key: string;
3879
+ label: string;
3880
+ losses: number;
3881
+ net_profit_display?: string;
3882
+ net_profit_usd?: number;
3883
+ pending: number;
3884
+ picks: number;
3885
+ priced_decided: number;
3886
+ priced_in_display?: string;
3887
+ priced_in_pct?: number;
3888
+ roi_display?: string;
3889
+ roi_pct?: number;
3890
+ settled: number;
3891
+ small_sample: boolean;
3892
+ staked_usd: number;
3893
+ unit_score?: number;
3894
+ unit_score_display?: string;
3895
+ void: number;
3896
+ win_rate_display?: string;
3897
+ win_rate_pct?: number;
3898
+ wins: number;
3899
+ }[];
3900
+ total_sides?: {
3901
+ canonical_category?: string;
3902
+ clv_avg_display?: string;
3903
+ clv_avg_pct?: number;
3904
+ clv_avg_pp?: number;
3905
+ clv_avg_pp_display?: string;
3906
+ clv_measured: number;
3907
+ edge_display?: string;
3908
+ edge_pp?: number;
3909
+ key: string;
3910
+ label: string;
3911
+ losses: number;
3912
+ net_profit_display?: string;
3913
+ net_profit_usd?: number;
3914
+ pending: number;
3915
+ picks: number;
3916
+ priced_decided: number;
3917
+ priced_in_display?: string;
3918
+ priced_in_pct?: number;
3919
+ roi_display?: string;
3920
+ roi_pct?: number;
3921
+ settled: number;
3922
+ small_sample: boolean;
3923
+ staked_usd: number;
3924
+ unit_score?: number;
3925
+ unit_score_display?: string;
3926
+ void: number;
3927
+ win_rate_display?: string;
3928
+ win_rate_pct?: number;
3929
+ wins: number;
3930
+ }[];
3931
+ view: string;
3932
+ voids?: {
3933
+ backed_price?: number;
3934
+ backed_side?: string;
3935
+ category?: string;
3936
+ matchup?: string;
3937
+ pick_date: string;
3938
+ pick_id: string;
3939
+ pick_rank: number;
3940
+ }[];
3941
+ };
3358
3942
  /** A settled uncommitted pick's market, side and price. The same eight fields as PickOfTheDayCommitmentPayload, in the same key order, so a settled pick's side and price sit under payload whatever the entry's state. It is NOT a commitment: no hash was taken over it before the game, and it proves nothing about when the pick was made. */
3359
3943
  export type PickOfTheDayUncommittedPayload = {
3360
3944
  /** Frozen pre-game price of the backed side, 0..1, as the plain decimal text of the stored NUMERIC at full stored precision, trailing zeros included -- rendered exactly as the commitment payload renders it. */
@@ -4113,7 +4697,7 @@ export type Trader = {
4113
4697
  * @deprecated
4114
4698
  */
4115
4699
  realized?: number;
4116
- /** Unrealized P&L in USD of the wallet's open positions on its synced sports and esports markets, from the open-position aggregate (dated by the positions data_quality group). Each open position's market is judged when the aggregate is read (#32119), so a stored position on a market of another category (one that moved out of sports and esports, or one stored before its category was known) is left out. Before 2026-10-27 (#29366) it covered every Polymarket market. */
4700
+ /** Unrealized (mark-to-market) P&L in USD of the wallet's open positions on its synced sports and esports markets: Polymarket's cashPnl, current value minus cost, summed over the positions still held, from the open-position aggregate (dated by the positions data_quality group). It is the same figure as position_summary.unrealized_mtm on GET /api/v1/trader/{address}/context. It leaves out the realized P&L of partial sells on those markets, which pnl.in_scope.realized_pnl already counts; until 2026-11-02 (#32459) it added it, so pnl.in_scope.realized_pnl plus pnl.unrealized counted those sells twice. Each open position's market is judged when the aggregate is read (#32119), so a stored position on a market of another category (one that moved out of sports and esports, or one stored before its category was known) is left out. Before 2026-10-27 (#29366) it covered every Polymarket market. */
4117
4701
  unrealized?: number;
4118
4702
  /**
4119
4703
  * Deprecated since 2026-10-27 and never sent: its one member was the lossless counterpart of the retired pnl.realized (#29830).
@@ -4184,6 +4768,18 @@ export type Trader = {
4184
4768
  /** 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. Sports and esports only (#28827): a category outside them is omitted, as on GET /api/v1/trader/{address}/categories. */
4185
4769
  category_records?: CategorySkillV2[];
4186
4770
  category_skill_model?: CategorySkillModelReadiness;
4771
+ /** Edge over the price paid: the profile's Edge badge and the leaderboard's Edge measure (#32622). Present on every read of a wallet with at least one settled sports or esports market of $20 or more at a known entry price; omitted for a wallet with none, where there is nothing to measure. */
4772
+ price_edge?: TraderPriceEdge;
4773
+ /** The profile's strategy measures over the wallet's sports and esports markets: P&L and win rate by UTC hour, hold-time and first-trade-hour bands, position sizes with category concentration, and entry-price buckets (#32622). Present only when expand=breakdowns or expand[]=breakdowns is requested, on GET /api/v1/trader/{address} only: POST /api/v1/traders/batch refuses the expand. Computed on the read from the wallet's whole sports and esports history, so a large wallet can take seconds; a read that cannot finish answers 503 with Retry-After. */
4774
+ breakdowns?: TraderBreakdowns;
4775
+ };
4776
+ /** The profile's strategy measures (expand=breakdowns, #32622), the same figures as the wallet profile's Insights and Performance breakdown cards. Every figure counts the wallet's sports and esports markets only, from the same read the profile makes. */
4777
+ export type TraderBreakdowns = {
4778
+ hourly_performance: TraderHourlyPerformance;
4779
+ time_breakdowns: TraderTimeBreakdowns;
4780
+ /** Position sizes and category concentration. null when the wallet has no sports or esports position with trades, or its stored markets carry no freshness clock yet. */
4781
+ risk_metrics: TraderRiskMetrics | null;
4782
+ entry_price_analysis: TraderEntryPriceAnalysis;
4187
4783
  };
4188
4784
  export type TraderCategoryRecord = {
4189
4785
  /** Canonical category bucket, for example Soccer, Esports, Tennis. Esports is one bucket, and the Esports record carries its per-game records in games. */
@@ -4237,7 +4833,7 @@ export type TraderContext = {
4237
4833
  synced_realized_pnl: number;
4238
4834
  /** Native net realized P&L (USD) over every Polymarket market of the wallet, including credited rebates, read directly from the accounting snapshot. For the sports and esports figure read trader.pnl.in_scope.realized_pnl. Position sync_coverage is separate from this accounting basis. */
4239
4835
  total_realized_pnl: number;
4240
- /** Mark-to-market unrealized P&L (USD) on open positions in synced sports and esports markets (#32119). */
4836
+ /** Mark-to-market unrealized P&L (USD) on open positions in synced sports and esports markets (#32119): Polymarket's cashPnl summed over the positions still held, without the realized P&L of partial sells. The same figure as trader.pnl.unrealized, in this body and on GET /api/v1/trader/{address}, since 2026-11-02 (#32459). */
4241
4837
  unrealized_mtm: number;
4242
4838
  /** Cost basis (USD) currently tied up in open positions in synced sports and esports markets (#32119). */
4243
4839
  cost_basis_locked: number;
@@ -4255,6 +4851,56 @@ export type TraderContext = {
4255
4851
  /** 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 can include settled markets recorded after the last full sync; native realized P&L follows its accounting snapshot -- not a live feed; re-fetch for fresher data). */
4256
4852
  freshness_note: string;
4257
4853
  };
4854
+ /** Results by the entry price the wallet paid for the side it held, over its settled sports and esports positions with a held entry price. coverage counts the settled positions the buckets leave out, and why. */
4855
+ export type TraderEntryPriceAnalysis = {
4856
+ /** One bucket per price band that has a market, in bucket_order. */
4857
+ buckets: TraderEntryPriceBucket[];
4858
+ /** The bucket with the highest win rate among buckets of at least 3 markets. null when no bucket has 3. */
4859
+ best_bucket: string | null;
4860
+ /** The bucket with the lowest win rate among buckets of at least 3 markets. null when no bucket has 3. */
4861
+ worst_bucket: string | null;
4862
+ /** What the buckets cover (since 2026-11-03, #32671). */
4863
+ coverage: TraderEntryPriceCoverage;
4864
+ };
4865
+ /** One entry-price band. Each measure is an analytic value: read state before value. */
4866
+ export type TraderEntryPriceBucket = {
4867
+ /** The band: $0.00-$0.19 (any price below $0.20, sub-cent fills included), $0.20-$0.39, $0.40-$0.59, $0.60-$0.79 or $0.80-$0.99. Until 2026-11-03 the first band was $0.01-$0.19 and sub-cent fills had no bucket (#32671). */
4868
+ bucket: string;
4869
+ /** Display position, 0 first, from the lowest price up. */
4870
+ bucket_order: number;
4871
+ /** Markets in the band. */
4872
+ markets: AnalyticInteger;
4873
+ /** Of those, the markets that made money. */
4874
+ wins: AnalyticInteger;
4875
+ /** wins over decided markets (a nonzero P&L), as a percentage 0-100. */
4876
+ win_rate: AnalyticNumber;
4877
+ /** Realized P&L of the band's markets, USD. */
4878
+ total_pnl: AnalyticNumber;
4879
+ /** Mean realized P&L of a market in the band, USD. */
4880
+ avg_pnl: AnalyticNumber;
4881
+ };
4882
+ /** The settled sports and esports positions the entry-price section reads. The buckets' markets plus every unbucketed row's are settled_markets, and their realized P&L sums to settled_pnl. settled_pnl adds up the wallet's per-market realized P&L, so it differs from pnl.in_scope.realized_pnl, which is Polymarket's published sports and esports P&L with a share of the wallet's rebates. */
4883
+ export type TraderEntryPriceCoverage = {
4884
+ /** Settled sports and esports positions: bucketed_markets plus every unbucketed row's markets. */
4885
+ settled_markets: number;
4886
+ /** Realized P&L of those positions, USD. */
4887
+ settled_pnl: number;
4888
+ /** Positions in a bucket: the sum of buckets[].markets. */
4889
+ bucketed_markets: number;
4890
+ /** Realized P&L of the bucketed positions, USD: the sum of buckets[].total_pnl. */
4891
+ bucketed_pnl: number;
4892
+ /** The settled positions the buckets leave out: one row for each reason that has a position, ordered by reason. Empty when the buckets hold every settled position. */
4893
+ unbucketed: TraderEntryPriceUnbucketed[];
4894
+ };
4895
+ /** Settled positions with no entry-price bucket, for one reason. */
4896
+ export type TraderEntryPriceUnbucketed = {
4897
+ /** two_sided: both outcomes bought at a price, a hedged book with no single side. held_side_unpriced: one outcome has a recorded price, but the wallet's remaining shares are on the other. no_entry_price: no outcome has a recorded entry price. freshness_unknown: a bucket whose rows carry no freshness clock yet. */
4898
+ reason: "two_sided" | "held_side_unpriced" | "no_entry_price" | "freshness_unknown";
4899
+ /** Positions left out for this reason. */
4900
+ markets: number;
4901
+ /** Their realized P&L, USD. */
4902
+ total_pnl: number;
4903
+ };
4258
4904
  export type TraderEsportsGameRecord = {
4259
4905
  /** 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. */
4260
4906
  game: string;
@@ -4428,6 +5074,36 @@ export type TraderGradeAt = {
4428
5074
  source_observed_by: string | null;
4429
5075
  } | null;
4430
5076
  };
5077
+ /** P&L and win rate by the UTC hour of the wallet's first trade in each settled sports or esports market. */
5078
+ export type TraderHourlyPerformance = {
5079
+ /** One entry per UTC hour that has a settled market; an hour with none is absent. */
5080
+ entries: ({
5081
+ /** UTC hour of the first trade, 0-23. */
5082
+ hour: number;
5083
+ /** Settled markets first traded in this hour. */
5084
+ markets: number;
5085
+ /** Of those, the markets that made money at settlement. */
5086
+ wins: number;
5087
+ /** wins over the decided markets (settled with a nonzero P&L), as a percentage 0-100. 0 when no market of the hour is decided: read it with wins and markets. */
5088
+ win_rate: number;
5089
+ /** Realized P&L of those markets, USD. */
5090
+ total_pnl: number;
5091
+ /** total_pnl over markets, USD. */
5092
+ avg_pnl: number;
5093
+ })[];
5094
+ /** The hour with the highest win_rate. null when no entry exists. */
5095
+ best_hour: number | null;
5096
+ /** best_hour's win_rate, percentage 0-100. null exactly when best_hour is. */
5097
+ best_win_rate: number | null;
5098
+ /** The hour with the lowest win_rate. null when no entry exists. */
5099
+ worst_hour: number | null;
5100
+ /** worst_hour's win_rate, percentage 0-100. null exactly when worst_hour is. */
5101
+ worst_win_rate: number | null;
5102
+ /** best_win_rate minus worst_win_rate, percentage points. null when either is null. */
5103
+ spread_pp: number | null;
5104
+ /** true when at least 12 hours have markets and every one of them has the same P&L sign, so the hour-to-hour spread says little about timing. */
5105
+ is_approximate: boolean;
5106
+ };
4431
5107
  /** A trader's sports and esports daily P&L object. `id`, `freshness_at`, `series_status` and `realized` are always present. The five sections -- `entries`, `stats`, `monthly`, `year_totals`, `drawdown` -- are present unless the request's `sections` parameter excluded them, so a request that sends no `sections` always carries all five. An excluded section is absent from the object, never null and never an empty array. While `series_status` is `pending` the sections are empty and never mean zero. */
4432
5108
  export type TraderPnl = {
4433
5109
  /** Prefixed trader ID (`trd_...`). */
@@ -4581,6 +5257,40 @@ export type TraderPnlInScope = {
4581
5257
  /** When the record behind these figures was computed. */
4582
5258
  as_of: string;
4583
5259
  };
5260
+ /** Edge over the price paid (#32270, #32622): how often the side a wallet bought won, minus the average price it paid, over its settled sports and esports markets of $20 or more at a known entry price. Probabilities throughout: edge 0.012 is 1.2 percentage points. The same figures as LeaderboardPriceEdge, plus the shrunk edge the profile badge and the leaderboard show. No hold: a hold is a fact of a leaderboard row, not of the wallet. */
5261
+ export type TraderPriceEdge = {
5262
+ /** Settled sports and esports markets of $20 or more at a known entry price that the edge is measured over. */
5263
+ markets: number;
5264
+ /** Share of those markets whose bought side won, 0-1. */
5265
+ hit_rate: number;
5266
+ /** Mean entry price paid, 0-1. */
5267
+ avg_price: number;
5268
+ /** hit_rate minus avg_price, full precision, before any shrink. */
5269
+ edge: number;
5270
+ /** Whether the edge ranks. ranked: at least 30 such markets, and the share of the decided ones that made money at settlement within 10 points of the win rate over the same markets. too_few_markets: fewer than 30. sample_mismatch: that share is more than 10 points away, so these markets do not describe the wallet's record. */
5271
+ status: "ranked" | "too_few_markets" | "sample_mismatch";
5272
+ /** The edge the profile badge shows and the leaderboard ranks: edge pulled toward field_average by how short the record is. A short record moves most of the way to the average; a long one keeps nearly all of its own edge. Present only when status is ranked. */
5273
+ shrunk_edge?: number;
5274
+ /** The mean edge of every ranked wallet that traded in the last 180 days, the value shrunk_edge is pulled toward. Present only with shrunk_edge. */
5275
+ field_average?: number;
5276
+ };
5277
+ /** Position sizes over the wallet's sports and esports positions with trades, and how concentrated its volume is across categories. Each measure is an analytic value: read state before value. The four size measures are not_computed while any position's cost is unknown; the counts are always measured. */
5278
+ export type TraderRiskMetrics = {
5279
+ /** Mean cost basis of a position, USD. */
5280
+ avg_position_size: AnalyticNumber;
5281
+ /** Median cost basis of a position, USD. */
5282
+ median_position_size: AnalyticNumber;
5283
+ /** Largest cost basis of a position, USD. */
5284
+ max_position_size: AnalyticNumber;
5285
+ /** Population standard deviation of the cost basis, USD. */
5286
+ position_size_stddev: AnalyticNumber;
5287
+ /** Sports and esports positions with trades. */
5288
+ total_positions: number;
5289
+ /** Positions whose cost is more than twice the mean. */
5290
+ large_position_count: number;
5291
+ /** Herfindahl index of the wallet's volume across sports and esports categories: each category's share of the volume, squared and summed. 1.0 is a single category; lower is more spread. not_computed while any category's cost is unknown, and no value without volume. */
5292
+ concentration: AnalyticNumber;
5293
+ };
4584
5294
  /** Lossless counterparts for trader statistics. The object is present exactly when stats.total_volume is. */
4585
5295
  export type TraderStatsExact = {
4586
5296
  /** stats.total_volume as an exact decimal: the sports and esports USD volume, the sum of every stored trade day's `trader_trade_daily_rollups.in_scope_volume_total` (#29830). Polymarket's full-history wallet-wide user volume before 2026-10-27. */
@@ -4593,6 +5303,30 @@ export type TraderSyncedData = {
4593
5303
  /** Proxy wallet address. */
4594
5304
  wallet: string;
4595
5305
  };
5306
+ /** One band of a time breakdown. */
5307
+ export type TraderTimeBreakdownBand = {
5308
+ /** The band's label. */
5309
+ category_value: string;
5310
+ /** Markets with a realized P&L in the band. */
5311
+ n_markets: number;
5312
+ /** Resolved markets that made money over resolved markets with a nonzero P&L, 0-1. null when none is decided. */
5313
+ win_rate: number | null;
5314
+ /** total_pnl over n_markets, USD. */
5315
+ expectancy: number | null;
5316
+ /** Gross profit over gross loss. null when the band has no loss. */
5317
+ profit_factor: number | null;
5318
+ /** Realized P&L of the band's markets, USD. */
5319
+ total_pnl: number | null;
5320
+ };
5321
+ /** The hold-time and first-trade-hour bands of the profile's Performance breakdown card, over the wallet's sports and esports markets with a realized P&L. */
5322
+ export type TraderTimeBreakdowns = {
5323
+ /** One row per band of time from the wallet's first to its last trade in a market: < 1h, 1h – 1d, 1 – 3d, 3 – 7d, 1 – 4w, > 4w. A band with no market is absent. */
5324
+ by_duration: TraderTimeBreakdownBand[];
5325
+ /** One row per four-hour UTC band of the wallet's first trade in a market: 00-03, 04-07, 08-11, 12-15, 16-19, 20-23. A band with no market is absent. */
5326
+ by_hour_bucket: TraderTimeBreakdownBand[];
5327
+ /** One-line summaries keyed by breakdown (by_duration, by_hour_bucket), from bands of at least 5 markets with a known P&L. A key is present only when there is a summary. */
5328
+ insights: Record<string, string>;
5329
+ };
4596
5330
  /** Field-level trust metadata returned only when GET /api/v1/trader/{address} includes expand=trust. */
4597
5331
  export type TraderTrust = {
4598
5332
  /** Since 2026-10-27 always not_computed: pnl.total is retired and never sent (#29830). The key stays so the object keeps its shape. */
@@ -5212,11 +5946,64 @@ export interface OperationData {
5212
5946
  getMarketTopHolders: MarketTopHolders;
5213
5947
  getMarketWalletsInOut: MarketWalletsInOut;
5214
5948
  getMonthlyReportSnapshot: ReportSnapshot;
5215
- getPickOfTheDay: PickOfTheDay | PickOfTheDayNoEntitledPicks;
5216
- getPickOfTheDayArchive: PickOfTheDayArchive;
5949
+ getPickOfTheDay: PickOfTheDay | PickOfTheDayNoEntitledPicks | {
5950
+ disclaimer?: string;
5951
+ locked_picks?: {
5952
+ pick_rank: number;
5953
+ required_tier: string;
5954
+ }[];
5955
+ pick_count: number;
5956
+ pick_date: string;
5957
+ picks: {
5958
+ backed_price?: number;
5959
+ category?: string;
5960
+ clv_pct?: number;
5961
+ clv_status?: string;
5962
+ display_category?: string;
5963
+ event_slug?: string;
5964
+ game_ended?: boolean;
5965
+ game_started?: boolean;
5966
+ holder_count?: number;
5967
+ is_free_selection: boolean;
5968
+ matchup?: string;
5969
+ outcome?: string;
5970
+ pick_id: string;
5971
+ pick_outcome_label?: string;
5972
+ polymarket_url?: string;
5973
+ publication_order: number;
5974
+ release_at?: string;
5975
+ return_usd?: number;
5976
+ stake_usd?: number;
5977
+ token_id?: string;
5978
+ top_grade?: string;
5979
+ unit_score?: number;
5980
+ }[];
5981
+ proof_pending_picks?: ({
5982
+ is_free_selection: boolean;
5983
+ kickoff?: string;
5984
+ pick_id: string;
5985
+ pick_rank: number;
5986
+ publication_order: number;
5987
+ release_at: string;
5988
+ retry_at: string;
5989
+ supersedes_pick_id: string | null;
5990
+ })[];
5991
+ scheduled_picks?: ({
5992
+ is_free_selection: boolean;
5993
+ kickoff: string;
5994
+ pick_id: string;
5995
+ pick_rank: number;
5996
+ publication_order: number;
5997
+ release_at: string;
5998
+ supersedes_pick_id: string | null;
5999
+ })[];
6000
+ state: string;
6001
+ view: string;
6002
+ };
6003
+ getPickOfTheDayArchive: PickOfTheDayArchive | PickOfTheDayArchiveSummary;
5217
6004
  getPickOfTheDayLedger: PickOfTheDayLedger;
5218
6005
  getPickOfTheDayLedgerEntry: PickOfTheDayLedgerEntry;
5219
- getPickOfTheDayStats: PickOfTheDayStats;
6006
+ getPickOfTheDayStats: PickOfTheDayStats | PickOfTheDayStatsSections;
5220
6007
  getPlatforms: Platforms;
5221
6008
  getPositionTimeline: PositionTimelineEvent[];
5222
6009
  getPositionTimelineById: PositionTimelineEvent[];
@@ -5559,7 +6346,7 @@ export interface OperationQuery {
5559
6346
  createWebhookVerificationAttempt: Record<string, never>;
5560
6347
  deleteWebhook: Record<string, never>;
5561
6348
  exploreMarkets: {
5562
- /** 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. Facet values are returned as the canonical bucket. Sports and esports only (#27411): a category outside them returns 400 bad_request with param category and names the accepted buckets. */
6349
+ /** 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. Facet values are returned as the canonical bucket. Sports and esports only (#27411): a category outside them returns 400 bad_request with param category and names the accepted buckets. The word sports, in any casing, matches every sport but Esports, the provider's catch-all Sports category (cycling, lacrosse) included: use esports for Esports alone, or omit category for both (#32657). The Sports facet counts that catch-all category alone. */
5563
6350
  category?: string;
5564
6351
  /** Filter by market status. A market is closed once Polymarket has closed trading or it has resolved, and active otherwise; all returns both. */
5565
6352
  status?: "active" | "closed" | "all";
@@ -5596,12 +6383,12 @@ export interface OperationQuery {
5596
6383
  getEdgeHunter: {
5597
6384
  /** Response mode. board preserves the full quoted board; signals exposes ranked records and category evidence; observations exposes cohort measurements and accountable funnel evidence. Defaults to board. */
5598
6385
  view?: "board" | "signals" | "observations";
5599
- /** Legacy canonical bucket alias, now accepted in every view. Provider aliases canonicalize: NFL reaches Football and EPL reaches Soccer. Use leagues for a league-specific selection. An unmappable non-sport category returns an empty result and echoes category non_sport. Combines with other selection axes using AND. */
6386
+ /** Legacy canonical bucket alias, now accepted in every view. Provider aliases canonicalize: NFL reaches Football and EPL reaches Soccer. Use leagues for a league-specific selection. The word sports, in any casing, reads as kind=sports, every sport but Esports, as category=sports does on every other route (#32720): the response echoes kind sports beside category sports, and with kind=esports it returns 400 with param category. Any other unmappable non-sport category returns an empty result and echoes category non_sport. Combines with other selection axes using AND. */
5600
6387
  category?: string;
5601
6388
  /** Required for view=observations; wider_holder, in_play or emerging_pile. Rejected for board and signals. wider_holder covers pregame markets that view=signals does not list at its widest selection (horizon_hours=48, min_grade=B, no selector), so until kickoff a market is read in one view or the other. A market view=signals lists leaves wider_holder as primary_slate_candidate, and is a wider_holder candidate again in the first refresh after view=signals stops listing it; signals_as_of names the view=signals snapshot each refresh read. Each refresh evaluates at most 8 markets per sport and cohort, wider_holder by soonest kickoff (most graded holders first among equal kickoffs) and in_play by most graded holders, so a market among a sport's 8 soonest stays evaluated until its game starts. wider_holder also evaluates up to 8 more markets per sport that kick off within 24 hours, most graded holders first, so the most-held markets appear up to a day before kickoff. Each of these keeps its place in later refreshes until its game starts while its holder page still shows a card or could not be read, so a more-held market waits for a free place instead of displacing it. Each row's admitted_by names its place, most_held or soonest_kickoff. The rest count in coverage.capacity_limited_markets. Emerging pile is a wider-holder projection with sharp_pct in [0.75,0.85), complete holder scans and future kickoff, not an independent population or arrival history. */
5602
6389
  cohort?: "wider_holder" | "in_play" | "emerging_pile";
5603
- /** Opt-in admission rule for view=observations with cohort=wider_holder; rejected for every other view and cohort. most_held_48h returns the most-held selection instead of the default one: per sport, up to 8 wider_holder markets kicking off within 48 hours, most graded holders first, then most volume, then soonest kickoff, at most 4 per event. It is recomputed every refresh and keeps no place, so a more-held market displaces a less-held one; markets view=signals lists stay excluded. Every row carries admitted_by most_held_48h, including a market the default selection also evaluates, and the response echoes admission. funnel, coverage, degraded and degradation_reasons describe this selection: a wider_holder candidate it did not take counts as capacity_limited. Its markets that no default place covers are read after every default market, at most once per 10 minutes, so a row can rest on a holder page up to 15 minutes old (holder_snapshot_at). Omit for the default selection. Cursors and ETags bind it. */
5604
- admission?: "most_held_48h";
6390
+ /** Opt-in admission rule for view=observations with cohort=wider_holder; rejected for every other view and cohort. most_held_48h returns the most-held selection instead of the default one: per sport, up to 8 wider_holder markets kicking off within 48 hours, most graded holders first, then most volume, then soonest kickoff, at most 4 per event. It is recomputed every refresh and keeps no place, so a more-held market displaces a less-held one; markets view=signals lists stay excluded. Every row carries admitted_by most_held_48h, including a market the default selection also evaluates, and the response echoes admission. funnel, coverage, degraded and degradation_reasons describe this selection: a wider_holder candidate it did not take counts as capacity_limited. Its markets that no default place covers are read after every default market, at most once per 10 minutes, so a row can rest on a holder page up to 15 minutes old (holder_snapshot_at). most_held_48h_by_type requires market_types and runs the same rule within each named type: per sport and market_context.market_type, up to 8 markets (4 per event), most graded holders first, then volume, then soonest kickoff, so a type whose markets hold fewer wallets than team-win markets still gets its own places. Its rows carry admitted_by most_held_48h_by_type and it has no departures. Its markets no other selection read are read after every default and most_held_48h market, at most once per 10 minutes. A market type not asked for in the last 30 minutes answers 503 read_model_warming with Retry-After 45 s while the next refresh computes it. Omit for the default selection. Cursors and ETags bind it. */
6391
+ admission?: "most_held_48h" | "most_held_48h_by_type";
5605
6392
  /** Board and signals: S, A or B, default B. Requires a piled-side holder at the selected grade floor or better, without removing other holders. Rejected for observations. */
5606
6393
  min_grade?: "S" | "A" | "B";
5607
6394
  /** Board row cap defaults to 30 and clamps integer values to 1..30; total counts selected admitted rows before the cap. Signals and observations page size defaults to 20 and clamps to 1..100. */
@@ -5702,11 +6489,29 @@ export interface OperationQuery {
5702
6489
  getPickOfTheDay: {
5703
6490
  /** A product day (America/New_York) in YYYY-MM-DD format, on or before today. Omit it, or send today, for the current read. A past day with no published pick returns 404 not_found with error.param=date; a date after today, or a value that is not a date, returns 400 bad_request with error.param=date. */
5704
6491
  date?: string;
6492
+ /** full (default) is the whole recorded set: every pick with its holders, lead backer, sports context, thesis and entry_authorization, and the top-level copy of the first pick. summary returns pick_date, pick_count, the disclaimer once, and each entitled pick's identity, side, price, result, return and grade (pick_id, publication_order, is_free_selection, matchup, category, display_category, event_slug, polymarket_url, token_id, pick_outcome_label, outcome, backed_price, stake_usd, return_usd, unit_score, top_grade, holder_count, clv_status, clv_pct, release_at, game_started, game_ended), with the same scheduled_picks, proof_pending_picks and locked_picks. The locked-only state=none body is the same in both views. Any other value returns 400 bad_request with error.param=view. */
6493
+ view?: "full" | "summary";
6494
+ /** One entitled published pick of the day, by its stable decimal-string pick_id. The body is the usual set holding that pick alone, without scheduled_picks, proof_pending_picks or locked_picks. Pair it with date for a past day's pick. A pick_id that is not among the day's entitled published picks returns 404 not_found with error.param=pick_id; one whose holder proof is not readable yet returns 503 read_model_warming with Retry-After; a value that is not a positive canonical decimal returns 400 bad_request with error.param=pick_id. */
6495
+ pick_id?: string;
6496
+ };
6497
+ getPickOfTheDayArchive: {
6498
+ /** full (default) is every row with every field, plus days and hit_rate with its per-pick series. summary returns view, hit_rate without series, one page of short rows (pick_id, pick_date, publication_order, is_free_selection, matchup, display_category, pick_outcome_label, outcome, top_grade, backed_price, unit_score, clv_pct, backed_side_locked, required_tier) and page; it always pages, 50 rows unless limit says otherwise. Any other value returns 400 bad_request with error.param=view. */
6499
+ view?: "full" | "summary";
6500
+ /** Rows per page of picks, 1 to 200, default 50. An integer outside that range is clamped into it, like every list limit, and X-Effective-Query reports the limit applied; a value that is not an integer returns 400 invalid_query. On view=full, sending limit or cursor pages picks and adds page, while days and hit_rate still describe the whole record; with neither, the response is the whole record. */
6501
+ limit?: number;
6502
+ /** The page.next_cursor of the previous page: the rows after it, newest first. A cursor is a position in the record, so a pick published while you page does not shift later pages. A value this route did not return returns 400 bad_request with error.param=cursor. */
6503
+ cursor?: string;
5705
6504
  };
5706
- getPickOfTheDayArchive: Record<string, never>;
5707
6505
  getPickOfTheDayLedger: Record<string, never>;
5708
6506
  getPickOfTheDayLedgerEntry: Record<string, never>;
5709
- getPickOfTheDayStats: Record<string, never>;
6507
+ getPickOfTheDayStats: {
6508
+ /** full (default) is every section. summary returns view, sections and every section except the five that grow with the record: series, days, categories, months and voids. In summary and sections bodies hit_rate carries no series; series is its own top-level section. Ignored when sections is sent. Any other value returns 400 bad_request with error.param=view. */
6509
+ view?: "full" | "summary";
6510
+ /** Exactly the sections to return, in the body's order whatever the request order. Repeatable and comma-separated: hit_rate, series, market_expectations, outcome_stats, days, categories, sports, tiers, months, price_bands, market_types, total_sides, streaks, records, voids. The body names them in sections and carries view=sections. An unrecognized name returns 400 bad_request with error.param=sections rather than being ignored. */
6511
+ sections?: ("hit_rate" | "series" | "market_expectations" | "outcome_stats" | "days" | "categories" | "sports" | "tiers" | "months" | "price_bands" | "market_types" | "total_sides" | "streaks" | "records" | "voids")[];
6512
+ /** Backward-compatible bracket alias for sections, for clients that emit array keys. Repeatable and comma-separated, with the same names. */
6513
+ "sections[]"?: ("hit_rate" | "series" | "market_expectations" | "outcome_stats" | "days" | "categories" | "sports" | "tiers" | "months" | "price_bands" | "market_types" | "total_sides" | "streaks" | "records" | "voids")[];
6514
+ };
5710
6515
  getPlatforms: Record<string, never>;
5711
6516
  getPositionTimeline: {
5712
6517
  /** Market condition_id. One timeline per (trader, market). */
@@ -5762,15 +6567,15 @@ export interface OperationQuery {
5762
6567
  };
5763
6568
  getSuspiciousTrade: Record<string, never>;
5764
6569
  getTrader: {
5765
- /** Backward-compatible alias for expand. Repeatable: strategy, categories, trust. quant_metrics is accepted and returns nothing since 2026-10-27. */
5766
- "expand[]"?: ("strategy" | "categories" | "quant_metrics" | "trust")[];
5767
- /** Include heavy fields and trust metadata. Repeatable: strategy, categories, trust. quant_metrics is accepted and returns nothing since 2026-10-27. */
5768
- expand?: ("strategy" | "categories" | "quant_metrics" | "trust")[];
5769
- /** Opt into a whole-response freshness ceiling in seconds. The server returns 200 only when data_quality.status is fresh and data_quality.as_of is no older than this value; otherwise it returns 409 with error.reason=freshness_ceiling_unsatisfied. No refresh or alternate read is attempted. */
6570
+ /** Backward-compatible alias for expand. Repeatable: strategy, categories, trust, breakdowns. quant_metrics is accepted and returns nothing since 2026-10-27. */
6571
+ "expand[]"?: ("strategy" | "categories" | "quant_metrics" | "trust" | "breakdowns")[];
6572
+ /** Include heavy fields and trust metadata. Repeatable: strategy, categories, trust, breakdowns. breakdowns adds the profile's strategy measures (Trader.breakdowns), computed on the read, and is served on this route only. quant_metrics is accepted and returns nothing since 2026-10-27. */
6573
+ expand?: ("strategy" | "categories" | "quant_metrics" | "trust" | "breakdowns")[];
6574
+ /** Opt into a whole-response freshness ceiling in seconds. The server returns 200 only when data_quality.status is fresh or stale and data_quality.as_of is no older than this value; otherwise it returns 409 with error.reason=freshness_ceiling_unsatisfied. No refresh or alternate read is attempted. */
5770
6575
  max_age_s?: number;
5771
6576
  };
5772
6577
  getTraderCategoryRecords: {
5773
- /** 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 sports or esports category the wallet has no record in answers 200 with an empty records array, never 404. Sports and esports only (#27311): a category outside them, or a value that reaches no category, returns 400 bad_request with param category and names the accepted buckets. */
6578
+ /** 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 sports or esports category the wallet has no record in answers 200 with an empty records array, never 404. Sports and esports only (#27311): a category outside them, or a value that reaches no category, returns 400 bad_request with param category and names the accepted buckets. The word sports, in any casing, matches every sport but Esports, the provider's catch-all Sports category (cycling, lacrosse) included: use esports for Esports alone, or omit category for both (#32657). */
5774
6579
  category?: string;
5775
6580
  };
5776
6581
  getTraderContext: Record<string, never>;
@@ -5891,7 +6696,7 @@ export interface OperationQuery {
5891
6696
  cursor?: string;
5892
6697
  /** Minimum position value in USD. Raises the feed's own floor of 50,000 USD; a smaller value does not lower it. */
5893
6698
  min_size?: number;
5894
- /** 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. A value outside sports and esports returns 400 bad_request with param=category (#27305), as on GET /api/v1/markets/explore. */
6699
+ /** 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. A value outside sports and esports returns 400 bad_request with param=category (#27305), as on GET /api/v1/markets/explore. The word sports, in any casing, names every sport and returns 400 bad_request with param category, because this filter takes one category: omit category for every sports and esports market, or name one sport (#32657). */
5895
6700
  category?: string;
5896
6701
  /** Minimum trader grade. Matched against the trader.grade each row returns, the wallet's current grade, so every row listed shows a grade at or above this floor. */
5897
6702
  min_grade?: "S" | "A" | "B" | "C" | "D" | "F";
@@ -5925,7 +6730,7 @@ export interface OperationQuery {
5925
6730
  condition_id?: string;
5926
6731
  /** Trader wallet address, timestamp-suffixed wallet alias, username, or trd_-prefixed trader ID, resolved against the traders table. Unknown traders return an empty list. */
5927
6732
  trader?: string;
5928
- /** 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. Sports and esports only (#27430): a category outside them returns 400 bad_request with param category and names the accepted buckets. */
6733
+ /** 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. Sports and esports only (#27430): a category outside them returns 400 bad_request with param category and names the accepted buckets. The word sports, in any casing, matches every sport but Esports, the provider's catch-all Sports category (cycling, lacrosse) included: use esports for Esports alone, or omit category for both (#32657). */
5929
6734
  category?: string;
5930
6735
  /** 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. */
5931
6736
  min_grade?: "S" | "A" | "B" | "C" | "D" | "F";
@@ -5951,7 +6756,7 @@ export interface OperationQuery {
5951
6756
  cursor?: string;
5952
6757
  /** Minimum trade size in USD. */
5953
6758
  min_size?: number;
5954
- /** 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. Sports and esports only (#27430): a category outside them returns 400 bad_request with param category and names the accepted buckets. */
6759
+ /** 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. Sports and esports only (#27430): a category outside them returns 400 bad_request with param category and names the accepted buckets. The word sports, in any casing, matches every sport but Esports, the provider's catch-all Sports category (cycling, lacrosse) included: use esports for Esports alone, or omit category for both (#32657). */
5955
6760
  category?: string;
5956
6761
  /** Minimum trader grade. */
5957
6762
  min_grade?: "S" | "A" | "B" | "C" | "D" | "F";
@@ -5973,7 +6778,7 @@ export interface OperationQuery {
5973
6778
  limit?: number;
5974
6779
  /** Opaque lbv1_ pagination cursor from a prior response. It binds the finite score/address boundary to the committed leaderboard generation and the effective category/strategy filters, and on a sorted page to its sort, dir and activity. A cursor from another sort or dir is a 400 bad_request on cursor; one from another activity, category, strategy or generation is cursor_expired. Legacy, malformed, non-finite, and unsupported-version cursors are rejected. */
5975
6780
  cursor?: string;
5976
- /** Filter by category: a sport or esports bucket. Values are matched to canonical category buckets: league values fold into their sport (NBA and NCAAB into Basketball, NFL into Football). Mapped buckets are case-insensitive; passthrough buckets (Cricket, Sports) match case-sensitively against the provider-native bucket key, so use exact casing. Sports and esports only (#27306): a category outside them returns 400 bad_request with param category and names the accepted buckets. */
6781
+ /** Filter by category: a sport or esports bucket, matched case-insensitively. League values fold into their sport (NBA and NCAAB into Basketball, NFL into Football). Sports and esports only (#27306): a category outside them returns 400 bad_request with param category and names the accepted buckets. The word sports, in any casing, matches every sport but Esports, the provider's catch-all Sports category (cycling, lacrosse) included: use esports for Esports alone, or omit category for both (#32657). */
5977
6782
  category?: string;
5978
6783
  /** Filter by observed trading style. Current styles: two_sided, category_focused, high_activity, diversified, mixed, unclassified. Current styles count the wallet's sports and esports markets only. The ten archetype keys retired on 2026-10-01 (accumulator, algo_trader, arbitrageur, directional, event_driven, market_maker, momentum, scalper, speculator, swing_trader) are still accepted and match no wallet. Style describes recorded behavior; grade measures performance. */
5979
6784
  strategy?: "category_focused" | "diversified" | "high_activity" | "mixed" | "two_sided" | "unclassified";
@@ -5994,7 +6799,7 @@ export interface OperationQuery {
5994
6799
  consistency?: "live" | "snapshot";
5995
6800
  /** 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. */
5996
6801
  min_size?: number;
5997
- /** Exact match against provider-backed market_canonical.category. Sports and esports only (#27311): a category outside them returns 400 bad_request with param category and names the accepted buckets. */
6802
+ /** Exact match against provider-backed market_canonical.category. Sports and esports only (#27311): a category outside them returns 400 bad_request with param category and names the accepted buckets. The word sports, in any casing, names every sport and returns 400 bad_request with param category, because this filter takes one category: omit category for every sports and esports market, or name one sport (#32657). */
5998
6803
  category?: string;
5999
6804
  /** 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 or a resolved market returns []. A market outside sports and esports returns 404 not_found with error.reason=market_out_of_scope (#27311). Without condition_id the board and wallet reads list sports and esports markets only. */
6000
6805
  condition_id?: string;
@@ -6014,7 +6819,7 @@ export interface OperationQuery {
6014
6819
  limit?: number;
6015
6820
  /** 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. */
6016
6821
  cursor?: string;
6017
- /** 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. Sports and esports only (#27306): a category outside them returns 400 bad_request with param category and names the accepted buckets. */
6822
+ /** 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. Sports and esports only (#27306): a category outside them returns 400 bad_request with param category and names the accepted buckets. The word sports, in any casing, matches every sport but Esports, the provider's catch-all Sports category (cycling, lacrosse) included: use esports for Esports alone, or omit category for both (#32657). */
6018
6823
  category?: string;
6019
6824
  /** Filter by source platform. all is a request-side no-op. */
6020
6825
  platform?: "polymarket" | "all";
@@ -6034,7 +6839,7 @@ export interface OperationQuery {
6034
6839
  limit?: number;
6035
6840
  /** 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. */
6036
6841
  cursor?: string;
6037
- /** 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. Sports and esports only (#27306): a category outside them returns 400 bad_request with param category and names the accepted buckets. */
6842
+ /** 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. Sports and esports only (#27306): a category outside them returns 400 bad_request with param category and names the accepted buckets. The word sports, in any casing, matches every sport but Esports, the provider's catch-all Sports category (cycling, lacrosse) included: use esports for Esports alone, or omit category for both (#32657). */
6038
6843
  category?: string;
6039
6844
  /** Filter by source platform. all is a request-side no-op. */
6040
6845
  platform?: "polymarket" | "all";
@@ -6102,7 +6907,7 @@ export interface OperationQuery {
6102
6907
  condition_id?: string;
6103
6908
  /** Trader wallet address, timestamp-suffixed wallet alias, or username resolved against the traders table. Unknown traders return an empty list. */
6104
6909
  trader?: string;
6105
- /** 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. Sports and esports only (#27430): a category outside them returns 400 bad_request with param category and names the accepted buckets. */
6910
+ /** 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. Sports and esports only (#27430): a category outside them returns 400 bad_request with param category and names the accepted buckets. The word sports, in any casing, matches every sport but Esports, the provider's catch-all Sports category (cycling, lacrosse) included: use esports for Esports alone, or omit category for both (#32657). */
6106
6911
  category?: string;
6107
6912
  /** Minimum trader grade. */
6108
6913
  min_grade?: "S" | "A" | "B" | "C" | "D" | "F";
@@ -6128,7 +6933,7 @@ export interface OperationQuery {
6128
6933
  cursor?: string;
6129
6934
  /** Minimum trade size in USD. */
6130
6935
  min_size?: number;
6131
- /** 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. Sports and esports only (#27430): a category outside them returns 400 bad_request with param category and names the accepted buckets. */
6936
+ /** 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. Sports and esports only (#27430): a category outside them returns 400 bad_request with param category and names the accepted buckets. The word sports, in any casing, matches every sport but Esports, the provider's catch-all Sports category (cycling, lacrosse) included: use esports for Esports alone, or omit category for both (#32657). */
6132
6937
  category?: string;
6133
6938
  /** Minimum trader grade as of today (trader.grade). A means S or A, B means S, A or B. */
6134
6939
  min_grade?: "S" | "A" | "B" | "C" | "D" | "F";
@@ -6165,7 +6970,7 @@ export interface OperationQuery {
6165
6970
  cursor?: string;
6166
6971
  /** Filter by market status. A market is closed once Polymarket has closed trading or it has resolved, and active otherwise; all returns both. */
6167
6972
  status?: "active" | "closed" | "all";
6168
- /** Filter by category. Sports and esports only (#27411): a category outside them returns 400 bad_request with param category and names the accepted buckets. */
6973
+ /** Filter by category. Sports and esports only (#27411): a category outside them returns 400 bad_request with param category and names the accepted buckets. The word sports, in any casing, names every sport and returns 400 bad_request with param category, because this filter takes one category: omit category for every sports and esports market, or name one sport (#32657). */
6169
6974
  category?: string;
6170
6975
  };
6171
6976
  submitTraderExport: {
@@ -6458,7 +7263,7 @@ export interface OperationBody {
6458
7263
  batchGetTraders: {
6459
7264
  /** Trader identities to resolve in input order. */
6460
7265
  traders: string[];
6461
- /** Shared expand flags applied to every trader item. */
7266
+ /** Shared expand flags applied to every trader item. breakdowns is refused with 400 (param expand): it computes on the read per wallet, so GET /api/v1/trader/{address} serves it one wallet at a time. */
6462
7267
  expand?: ("strategy" | "categories" | "quant_metrics" | "trust")[];
6463
7268
  };
6464
7269
  cancelTraderExport: never;
@@ -6984,6 +7789,7 @@ export interface OperationResponse {
6984
7789
  /** Total matching rows when the read model exposes a count; the key is absent when it does not. */
6985
7790
  total?: number;
6986
7791
  meta: ResponseMeta;
7792
+ summary?: LeaderboardSummary;
6987
7793
  };
6988
7794
  listLeaderboardLeagues: {
6989
7795
  object: "leaderboard_leagues";