{
  "openapi": "3.1.0",
  "info": {
    "x-generated-rate-limit-policy-from": "web/src/lib/rate-limit-facts.ts via web/scripts/generate-api-policy.ts",
    "title": "0xinsider API",
    "description": "Follow provider-exposed large-trade activity on Polymarket sports and esports markets. The API serves sports and esports markets only: a market, event or trade outside them answers 404 not_found with error.reason=market_out_of_scope, which is terminal, so do not retry it, and a category outside them answers 400 bad_request with error.param=category, except on GET /api/v1/edge-hunter, where in every view a category that maps to no sport answers an empty result whose selection.category is non_sport. Polymarket wallet-attributed trades can add grades, P&L, strategy, and diagnostic-score context when sufficient source data exists. Fields can be null or unavailable. Normal API requests use a 30-second server timeout that returns HTTP 408 Request Timeout with the standard error envelope (error.code request_timeout) when exceeded. Every /api/v1 failure answers that envelope, including a body that is not JSON or does not fit the request schema (400 invalid_body), a query or path value that does not parse (400 invalid_query, invalid_path), a missing Content-Type: application/json (415 unsupported_media_type), a body over 1048576 bytes (413 payload_too_large) and a method the path does not serve (405 method_not_allowed), each with error.param naming the field where one is known and meta.request_id equal to X-Request-Id. Unknown query names are ignored by default and reported in X-Query-Ignored, while X-Effective-Query lists the normalized names and values applied using form-urlencoded decoding, where + is a space; strict mode returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including for an unknown name with an incomplete percent escape. Every list operation clamps an out-of-range limit into its published minimum..maximum instead of refusing it (limit=0 reads one row, limit=500 reads the maximum), and X-Effective-Query reports the clamped value; only a limit that is not an integer is refused, with 400 invalid_query. Public REST /api/v1/* endpoints, excluding /api/v1/mcp, use Bearer-token based non-credentialed browser CORS: any Origin may call with Authorization, Content-Type, If-None-Match, Idempotency-Key, Mcp-Session-Id, Mcp-Protocol-Version, Mcp-Method, Mcp-Name, Last-Event-Id, and X-Query-Validation request headers. X-Query-Validation: strict opts into rejecting unknown query names; the default remains compatible. Remote MCP at /api/v1/mcp is non-credentialed, but still validates Origin against the 0xinsider/localhost allowlist per MCP Streamable HTTP DNS-rebinding guidance. Successful browser CORS preflight responses advertise Access-Control-Max-Age: 86400. Browser JavaScript may read RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Retry-After, ETag, X-Request-Id, X-Request-Cost, X-Usage-Accounting, X-Batch-RateLimit-Limit, X-Batch-RateLimit-Remaining, X-Batch-RateLimit-Reset, X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, X-Monthly-Quota-Reset, X-Query-Ignored, X-Effective-Query, X-Query-Unmatched, Deprecation, Sunset, Link, and Server-Timing response headers. Rate-limit headers describe the budget a request was counted against: the API key's per-minute window, at its plan's limit, on an authenticated call, and the per-IP budget on a public route or on a refused credential (401, 402, 403, 423), so a client looping on a bad or lapsed key still sees how much room it has. Conditional GET: these operations return a weak ETag and answer If-None-Match with 304 Not Modified and an empty body: GET /api/v1/health, GET /api/v1/insider-radar, GET /api/v1/insider-radar/{id}, GET /api/v1/large-positions, GET /api/v1/leaderboard, GET /api/v1/leaderboard/trending, GET /api/v1/market/{condition_id}/candles, GET /api/v1/market/{condition_id}/flow, GET /api/v1/market/{condition_id}/intel, GET /api/v1/market/{condition_id}/snapshot, GET /api/v1/markets/explore, GET /api/v1/markets/sharp-money-flows, GET /api/v1/markets/smart-money-flows, GET /api/v1/pick-of-the-day, GET /api/v1/pick-of-the-day/archive, GET /api/v1/positions, GET /api/v1/trader/{address}, GET /api/v1/trader/{address}/context, GET /api/v1/trader/{address}/pnl, GET /api/v1/trader/{address}/position-timeline, GET /api/v1/traders/{trader}/position-timeline, GET /api/v1/large-trades, GET /api/v1/large-trades/history, GET /api/v1/large-trades/{id}, GET /api/v1/whale-trades, GET /api/v1/whale-trades/history, GET /api/v1/whale-trades/{id}, GET /api/v1/whale-trades/{id}/counterparties/executions, GET /api/v1/whale-trades/{id}/counterparties/executions/{execution_id}/makers. Credentialed first-party routes such as /api/keys, /api/billing, and auth endpoints remain restricted to configured 0xinsider origins. Protected V1 responses, except the zero-cost /api/v1/usage route, after handler execution carry X-Usage-Accounting: persisted, failed, or unknown. This reports the usage-record write; it does not change the handler result. Do not replay a successful mutation to repair an unknown usage record. Before execution, unavailable accounting capacity returns HTTP 503 with error.reason=request_accounting_unavailable; honor Retry-After. Public API responses add the browser-readable Server-Timing header: Processing time in milliseconds, for example api;dur=12.345. Includes API authentication, quota admission, handler work and response construction. Excludes network transit and streamed body or export-file transfer. The engineering budget is strictly below 250 ms; this header reports observations, not a latency guarantee or a new timeout. Requests through https://0xinsider.com/api/* append Server-Timing: web_api;dur=<milliseconds> and X-Web-Request-Id for that web origin handler. The web clock includes upstream waiting and existing body construction, so do not add it to api;dur. It excludes platform routing, cold module initialization, CDN hits and later stream/file transfer. On a cache hit these headers describe the earlier origin fill, not the current request; static Markdown API routes have no fresh web clock. GET /api/v1/edge-hunter supports conditional reads only with view=signals or view=observations; view=board does not emit ETag or return 304.",
    "version": "1.0.0",
    "contact": {
      "name": "0xinsider",
      "email": "support@0xinsider.com",
      "url": "https://0xinsider.com"
    }
  },
  "externalDocs": {
    "description": "0xinsider API docs",
    "url": "https://docs.0xinsider.com"
  },
  "servers": [
    {
      "url": "https://api.0xinsider.com",
      "description": "Production (live data). Authenticate with a live key (oxi_sk_live_...); requires an active Pro subscription. A sandbox key (oxi_sk_test_...) is answered with 401 invalid_api_key and error.reason sandbox_api_key."
    },
    {
      "url": "https://0xinsider.com/sandbox",
      "description": "Sandbox. No credential required and no production data: every documented operation answers with its documented example or a deterministic sample of its response schema. GET /api/v1/stream is the one exclusion and answers 400 there, because a Server-Sent Events stream is a live connection rather than a body. Add ?sandbox_status=<code> to receive one of the error responses the operation documents (for example 429 with Retry-After). Documented query parameters and JSON request bodies are checked against this document, the two context.md routes answer 200 text/markdown, GET /api/v1/trader/{address}/export/download answers its 302 with a Location the sandbox serves itself rather than an object store, and nothing is stored between requests. A sandbox key (oxi_sk_test_..., issued with no account by POST https://api.0xinsider.com/api/v1/agents/register) is optional: on an operation that requires a credential, a well-formed key is answered with X-Oxi-Sandbox-Key: valid and a malformed one with 401 invalid_api_key."
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "oauth2": ["read"]
    }
  ],
  "paths": {
    "/api/v1": {
      "get": {
        "operationId": "getApiDiscovery",
        "summary": "API discovery",
        "description": "Unauthenticated API-origin discovery document pointing agents to the canonical API base URL, full docs, web-origin OpenAPI spec, health check, and the COMPLETE index of authenticated data routes. data.authenticated_routes is the whole authenticated route surface, not a sample: it carries every authenticated route this spec documents, so an agent that starts here never has to guess a path. The index is a hand-maintained const in backend/src/api_v1/discovery.rs kept in step with this spec by review; no automated check compares the two, so treat this spec as authoritative if they ever disagree.",
        "tags": ["System"],
        "security": [],
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl 'https://api.0xinsider.com/api/v1'"
          }
        ],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "API discovery document",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "api_discovery"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ApiDiscovery"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "example": {
                  "object": "api_discovery",
                  "data": {
                    "api_base_url": "https://api.0xinsider.com",
                    "docs_url": "https://0xinsider.com/llms-full.txt",
                    "openapi_url": "https://0xinsider.com/api/v1/openapi.json",
                    "health_url": "https://api.0xinsider.com/api/v1/health",
                    "authentication": "Bearer API key required for data endpoints; discovery (/api/v1), health, coverage (/api/v1/coverage, and its deprecated alias /api/v1/platforms), the Pick of the Day commitment ledger (/api/v1/pick-of-the-day/ledger), and the MCP handshake (initialize, ping, tools/list on /api/v1/mcp) are public. A 401 carries WWW-Authenticate with the resource_metadata URL.",
                    "protected_resource_metadata_url": "https://api.0xinsider.com/.well-known/oauth-protected-resource",
                    "authenticated_routes": [
                      "GET /api/v1/leaderboard",
                      "GET /api/v1/content/search",
                      "GET /api/v1/markets/search",
                      "GET /api/v1/pick-of-the-day",
                      "GET /api/v1/positions",
                      "GET /api/v1/trader/{address}",
                      "GET /api/v1/whale-trades",
                      "POST /api/v1/traders/batch"
                    ]
                  },
                  "meta": {
                    "request_id": "req_550e8400-e29b-41d4-a716-446655440000",
                    "cached": false,
                    "cost": 1
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/openapi.json": {
      "get": {
        "operationId": "redirectApiOpenapiSpec",
        "summary": "Redirect to the canonical OpenAPI spec",
        "description": "Unauthenticated API-origin compatibility redirect to the canonical web-origin OpenAPI JSON document at https://0xinsider.com/api/v1/openapi.json.",
        "tags": ["System"],
        "security": [],
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -I 'https://api.0xinsider.com/api/v1/openapi.json'"
          }
        ],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          }
        ],
        "responses": {
          "307": {
            "description": "Temporary redirect to the canonical web-origin OpenAPI spec.",
            "headers": {
              "Location": {
                "description": "Canonical web-origin OpenAPI document.",
                "required": true,
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/agents/register": {
      "post": {
        "operationId": "registerAgent",
        "summary": "Register an agent for a sandbox key",
        "description": "Self-serve agent onboarding: no account, no request body, no human step. Returns a sandbox API key (oxi_sk_test_...) and the path to live access. The key works only on the sandbox server (https://0xinsider.com/sandbox/api/v1), where it is optional: send it as Authorization: Bearer to exercise the credential path, and the sandbox answers a malformed key with the production 401. Nothing is stored, so the key cannot be listed or revoked and does not expire; register again for a new one. The live API answers a sandbox key with 401 invalid_api_key and error.reason sandbox_api_key. Live data needs an account with an active Pro subscription, and either an oxi_sk_live_ key from https://0xinsider.com/developers or an OAuth access token (https://0xinsider.com/auth.md). The request body is not read.",
        "tags": ["Onboarding"],
        "security": [],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          }
        ],
        "responses": {
          "201": {
            "description": "A new sandbox key. Every call returns a different key, with Cache-Control: private, no-store.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "agent_registration"
                    },
                    "data": {
                      "$ref": "#/components/schemas/AgentRegistration"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "agent_registration",
                      "data": {
                        "api_key": "oxi_sk_test_<64 lowercase hex characters>",
                        "livemode": false,
                        "environment": "sandbox",
                        "created_at": "2026-09-14T12:00:00Z",
                        "sandbox": {
                          "api_base_url": "https://0xinsider.com/sandbox/api/v1",
                          "first_request_url": "https://0xinsider.com/sandbox/api/v1/leaderboard",
                          "openapi_url": "https://0xinsider.com/sandbox/api/v1/openapi.json"
                        },
                        "live_access": {
                          "api_base_url": "https://api.0xinsider.com/api/v1",
                          "requirement": "An 0xinsider account with an active Pro subscription. A person creates a live key (oxi_sk_live_) at api_keys_url, or approves an OAuth grant for a client registered at oauth_registration_endpoint.",
                          "api_keys_url": "https://0xinsider.com/developers",
                          "oauth_authorization_server_metadata_url": "https://api.0xinsider.com/.well-known/oauth-authorization-server",
                          "oauth_registration_endpoint": "https://api.0xinsider.com/oauth/register",
                          "pricing_url": "https://0xinsider.com/pricing",
                          "auth_guide_url": "https://0xinsider.com/auth.md"
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS -X POST 'https://api.0xinsider.com/api/v1/agents/register'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "agent_registration",
            "data": {
              "api_key": "oxi_sk_test_<64 lowercase hex characters>",
              "livemode": false,
              "environment": "sandbox",
              "created_at": "2026-09-14T12:00:00Z",
              "sandbox": {
                "api_base_url": "https://0xinsider.com/sandbox/api/v1",
                "first_request_url": "https://0xinsider.com/sandbox/api/v1/leaderboard",
                "openapi_url": "https://0xinsider.com/sandbox/api/v1/openapi.json"
              },
              "live_access": {
                "api_base_url": "https://api.0xinsider.com/api/v1",
                "requirement": "An 0xinsider account with an active Pro subscription. A person creates a live key (oxi_sk_live_) at api_keys_url, or approves an OAuth grant for a client registered at oauth_registration_endpoint.",
                "api_keys_url": "https://0xinsider.com/developers",
                "oauth_authorization_server_metadata_url": "https://api.0xinsider.com/.well-known/oauth-authorization-server",
                "oauth_registration_endpoint": "https://api.0xinsider.com/oauth/register",
                "pricing_url": "https://0xinsider.com/pricing",
                "auth_guide_url": "https://0xinsider.com/auth.md"
              }
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/trader/{address}": {
      "get": {
        "operationId": "getTrader",
        "summary": "Get trader",
        "description": "Returns a trader's grade (S through F), P&L, win rate, and optional strategy/category data. The path accepts either an Ethereum wallet address, a known trader username, or a trd_-prefixed trader ID emitted by this API. A wallet address this API does not track yet returns 200 with sync_status \"unknown\" instead of 404, so it can be polled. A value that is not a wallet address and matches no username or trader ID this API knows returns 404 not_found with error.param address; it is never echoed back as a trader address. The additive `stats.exact.total_volume` field carries a decimal string with unit, scale and basis metadata; parse it with decimal-safe arithmetic and keep the numeric twin for display. P&L and stats cover sports and esports markets only (#29830): `pnl.in_scope` (#27311) is the wallet's sports and esports record, the P&L the 0xinsider profile headlines, and `stats` counts the same markets. The wallet-wide `pnl.total`, `pnl.net_total`, `pnl.realized`, `pnl.exact`, `pnl.correction` and `stats.daily_win_rate` are deprecated and never sent since 2026-10-27; `pnl.unrealized` stays wallet-wide.",
        "tags": ["Traders"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "Ethereum wallet address (0x...), known trader username, or trd_-prefixed trader ID emitted by this API.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand[]",
            "in": "query",
            "required": false,
            "description": "Backward-compatible alias for expand. Repeatable: strategy, categories, trust, breakdowns. quant_metrics is accepted and returns nothing since 2026-10-27.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["strategy", "categories", "quant_metrics", "trust", "breakdowns"]
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "expand",
            "in": "query",
            "required": false,
            "description": "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.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["strategy", "categories", "quant_metrics", "trust", "breakdowns"]
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "max_age_s",
            "in": "query",
            "required": false,
            "description": "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.",
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Trader profile",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "trader"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Trader"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "trader",
                      "data": {
                        "id": "trd_0xabc1230000000000000000000000000000000abc",
                        "address": "0xabc1230000000000000000000000000000000abc",
                        "username": "example_trader",
                        "grade": "D",
                        "score": 40.17,
                        "forecast_score": 46.2,
                        "forecast_evidence": 0.38,
                        "streak_tier": "neutral",
                        "pnl": {
                          "unrealized": 135.56,
                          "in_scope": {
                            "basis": "polymarket_sports_esports_v1",
                            "realized_pnl": -1204.37,
                            "markets": 412,
                            "markets_resolved": 398,
                            "win_rate": 0.5812,
                            "markets_out_of_scope": 1477,
                            "as_of": "2026-09-10T04:18:02.551204Z"
                          }
                        },
                        "stats": {
                          "markets_traded": 412,
                          "win_rate": 0.5812,
                          "total_volume": 48210.55,
                          "exact": {
                            "total_volume": {
                              "value": "48210.551203",
                              "unit": "USD",
                              "scale": 6,
                              "basis": "trader_trade_daily_rollups.in_scope_volume_total (sum over every stored trade day; sports and esports markets)"
                            }
                          }
                        },
                        "strategy": {
                          "strategy_type": "mixed",
                          "description": "Mixed activity across 1,802 stored markets. No single observed behavior has a clear lead. Category shares describe recorded USD cost basis; style is separate from performance."
                        },
                        "last_active": "2026-09-09T21:47:12Z",
                        "synced_at": "2026-09-10T02:04:30.398422Z",
                        "sync_status": "synced",
                        "data_quality": {
                          "status": "partial",
                          "as_of": "2026-09-10T02:04:30.398422Z",
                          "field_groups": [
                            {
                              "group": "sync",
                              "owner": "traders.last_synced",
                              "status": "fresh",
                              "as_of": "2026-09-10T02:04:30.398422Z",
                              "max_age_s": 604800
                            },
                            {
                              "group": "sports_record",
                              "owner": "trader_product_scope_records.computed_at",
                              "status": "fresh",
                              "as_of": "2026-09-10T04:18:02.551204Z"
                            },
                            {
                              "group": "ranking",
                              "owner": "trader_rankings.computed_at",
                              "status": "fresh",
                              "as_of": "2026-09-10T06:12:44.120031Z",
                              "max_age_s": 604800
                            },
                            {
                              "group": "leaderboard_rank",
                              "owner": "leaderboard_rank_refresh_state.completed_at",
                              "status": "untracked",
                              "reason": "only S, A and B wallets are given a leaderboard rank"
                            },
                            {
                              "group": "volume",
                              "owner": "traders.last_synced",
                              "status": "fresh",
                              "as_of": "2026-09-10T02:04:30.398422Z",
                              "max_age_s": 604800
                            },
                            {
                              "group": "positions",
                              "owner": "trader_position_snapshots.last_refreshed_at|traders.last_synced",
                              "status": "unknown",
                              "reason": "open-position unrealized P&L is served, but no successful position snapshot or sync clock is available"
                            }
                          ]
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "409": {
            "description": "The opt-in max_age_s ceiling could not be met. error.reason is freshness_ceiling_unsatisfied; error.freshness carries the requested ceiling, the measured age when available, the stored as_of clock, and data_quality_status. No refresh or alternate read is attempted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "The address value names no trader: it is not a wallet address, and no username or trader ID this API knows matches it. error.code is not_found and error.param is address. A wallet address 0xinsider does not track yet is not an error; it returns 200 with sync_status \"unknown\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/trader/{address}'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "trader",
            "data": {},
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/trader/{address}/context.md": {
      "get": {
        "operationId": "getTraderContextMarkdown",
        "summary": "Get trader context (Markdown)",
        "description": "Returns a single human- and LLM-readable Markdown briefing for one trader: identity, grade, P&L, position coverage, and freshness. The path accepts an Ethereum wallet address (0x...), a known trader username, or a trd_-prefixed trader ID emitted by this API. A wallet address this API does not track yet still returns 200 with a degraded 'not yet synced' document (no 404). A value that is not a wallet address and matches no username or trader ID this API knows returns 404 not_found with error.param address, as the JSON error envelope. The Markdown variant does not emit an ETag and does not support conditional requests; use the JSON variant (drop the .md suffix) for ETag/If-None-Match handling.",
        "tags": ["Traders"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "Ethereum wallet address (0x...), known trader username, or trd_-prefixed trader ID emitted by this API.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Trader context document (Markdown)",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                },
                "example": "# Trader context: @swisstony\n\nAI-ready trader summary from 0xinsider. Reflects backend state as of the data_as_of clock below (a point-in-time snapshot, cached briefly), not request time.\n\n- Data as of: 2026-01-15T12:00:00Z\n- Sync status: synced\n"
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "The address value names no trader: it is not a wallet address, and no username or trader ID this API knows matches it. error.code is not_found and error.param is address. A wallet address 0xinsider does not track yet is not an error; it returns 200 with sync_status \"unknown\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable, with two causes; branch on error.reason. (1) error.reason=read_model_warming: the position_summary read ran past its time budget twice on database pages that were not cached (it reads every position row the wallet has, so a wallet with a long history is the usual case). The pages those reads reached stay cached, so a retry after Retry-After (2 s) normally succeeds. The context is never served without its position_summary for this reason, and a partial breakdown is never served. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the per-process outage cooldown. Both carry error.code=rate_limit_unavailable.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a retry is worth making: 2 for read_model_warming, the rate limiter's outage cooldown otherwise.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/trader/{address}/context.md'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/trader/{address}/grade-at": {
      "get": {
        "operationId": "getTraderGradeAt",
        "summary": "Get a trader grade proven visible at a past instant",
        "description": "Reads one trader's recorded grade at as_of from prospective visibility evidence. Before the first recorded observation, after deletion, or during a grade-transition gap, status is unknown and grade is null; a recorded ungraded trader instead has status ungraded. available_from is the first proven observation for this trader, not a claim that earlier grades can be reconstructed. observed_at is when the grade writer began the transition and published_by is the later confirmation that the row was committed, not an exact commit time. Older observations have null model_version, model_build_sha and source_observed_by; do not substitute a current grade or a dated ranking row. The requested event time, publication bounds and model provenance are separate. Use a grade only when status is graded. This is additive; the current-grade trader and leaderboard operations do not change.",
        "tags": ["Traders"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "Wallet address (0x...), username, or trd_-prefixed trader id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "as_of",
            "in": "query",
            "required": true,
            "description": "RFC3339 instant whose historically visible grade is requested. Future instants are refused. Send the trade or decision time, not the ranking date.",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-09-21T12:00:00Z"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Grade visibility at the requested instant, including explicit unknown coverage",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "trader_grade_at"
                    },
                    "data": {
                      "$ref": "#/components/schemas/TraderGradeAt"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "example": {
                  "object": "trader_grade_at",
                  "data": {
                    "id": "trd_0xabc1230000000000000000000000000000000abc",
                    "address": "0xabc1230000000000000000000000000000000abc",
                    "as_of": "2026-09-18T12:00:00Z",
                    "status": "unknown",
                    "grade": null,
                    "available_from": "2026-09-19T23:00:56Z",
                    "observation": null
                  },
                  "meta": {
                    "request_id": "req_example",
                    "cached": false,
                    "cost": 1
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/trader/{address}/clv": {
      "get": {
        "operationId": "getTraderClv",
        "summary": "Get a trader's closing line value on large trades",
        "description": "Closing line value (CLV) over one wallet's large trades in a window: the trades GET /api/v1/large-trades/history?trader= returns for the same from, to, min_size and category, each measured exactly as its clv object is. CLV is in cents per share against the market's stored closing line (GET /api/v1/market/{condition_id}/close): a buy scores the close minus the price paid, a sell the price received minus the close, so a positive value beat the close. Only trades filled before kickoff on a market with a measured close count; in-play, pending and unavailable trades are counted in excluded. measured gives the plain mean, the size-weighted mean, the share that beat the close, and the mean over markets with a normal 95% interval when there are two or more markets, since one wallet's fills in one game are not independent. Gross of fees. Large trades only (min_size defaults to 5000 USD), not every fill. The window defaults to the 90 days before to (which defaults to now) and spans at most 366 days; a window holding more than 25,000 large trades returns 400.",
        "tags": ["Traders"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "Wallet address (0x...), username, or trd_-prefixed trader id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Inclusive RFC3339 lower bound on the trade time. Defaults to 90 days before to.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Exclusive RFC3339 upper bound on the trade time. Defaults to now; must be after from, and at most 366 days after it.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "min_size",
            "in": "query",
            "description": "Minimum trade size in USD. The capture floor was 3,000 USD before 2026-07-06 and 10,000 USD from then (1,000 USD in earnings markets), so 10000 gives one size rule across the whole archive. From 2026-09-23 a fill must also be at least 0.1% of its market's recorded traded volume (Polymarket's own share count), where a positive volume is recorded for the market; a market without one keeps the fill, and rows written before that date were not re-filtered.",
            "schema": {
              "type": "number",
              "default": 5000
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "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).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The wallet's closing line value over its large trades in the window.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "trader_clv"
                    },
                    "data": {
                      "$ref": "#/components/schemas/TraderClv"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "example": {
                  "object": "trader_clv",
                  "data": {
                    "id": "trd_0xabc1230000000000000000000000000000000abc",
                    "address": "0xabc1230000000000000000000000000000000abc",
                    "from": "2026-08-06T00:00:00Z",
                    "to": "2026-11-04T00:00:00Z",
                    "min_size": 5000,
                    "category": null,
                    "basis_version": "clv@v1",
                    "large_trades": 42,
                    "measured": {
                      "trades": 30,
                      "markets": 21,
                      "size_usd": 412500.0,
                      "mean_clv_cents": 1.8,
                      "stake_weighted_clv_cents": 2.1,
                      "share_beat_close": 0.6333333333333333,
                      "market_mean_clv_cents": 1.6,
                      "market_ci95_cents": {
                        "low": -0.4,
                        "high": 3.6
                      }
                    },
                    "excluded": {
                      "in_play": 9,
                      "pending": 2,
                      "unavailable": 1
                    }
                  },
                  "meta": {
                    "request_id": "req_example",
                    "cached": false,
                    "cost": 1
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/trader/{address}/context": {
      "get": {
        "operationId": "getTraderContext",
        "summary": "Get trader context (JSON)",
        "description": "Returns a single structured context object for one trader: the full trader profile (same shape as GET /api/v1/trader/{address}) plus a position_summary (sync coverage and realized/unrealized P&L rollups, with an as_of open-position freshness clock), the data_as_of freshness timestamp (the open-position data's latest /positions snapshot, else last completed sync; the snapshot advances only open positions, so resolved counts and win rate still date to the last full sync; native realized P&L follows its accounting snapshot), and a freshness_note describing the point-in-time snapshot semantics. The path accepts an Ethereum wallet address (0x...), a known trader username, or a trd_-prefixed trader ID emitted by this API. position_summary is omitted when the trader is not in the local database or native net economics is unavailable; realized fields remain numeric when present; a wallet address this API does not track yet returns 200 with sync_status 'unknown' on the nested trader (no 404), while a value that is not a wallet address and matches no username or trader ID this API knows returns 404 not_found with error.param address. Append .md to the path for the Markdown rendering.",
        "tags": ["Traders"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "Ethereum wallet address (0x...), known trader username, or trd_-prefixed trader ID emitted by this API.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Trader context",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "trader_context"
                    },
                    "data": {
                      "$ref": "#/components/schemas/TraderContext"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "trader_context",
                      "data": {
                        "data_as_of": "2026-09-10T02:04:30.398422Z",
                        "freshness_note": "Point-in-time snapshot. data_as_of is the open-position clock -- the trader's latest position (/positions) snapshot, else the last completed sync. The snapshot advances only open positions; resolved counts and win rate can include settled markets recorded after the last full sync. Native realized P&L follows its accounting snapshot, whose freshness this clock does not establish. Not a live feed; re-fetch for fresher data.",
                        "trader": {
                          "address": "0xabc1230000000000000000000000000000000abc",
                          "category_records": [
                            {
                              "as_of": "2026-09-22T03:17:17.488299Z",
                              "brier_event_avg": null,
                              "canonical_category": "Esports",
                              "edge_lower_95": null,
                              "edge_mean": null,
                              "edge_sd": null,
                              "edge_se": null,
                              "independent_event_count": 0,
                              "latest_observation_at": null,
                              "model_version": "category-skill-v2.0.0",
                              "observation_started_at": "2026-09-01T21:50:07.762477Z",
                              "platform": "polymarket",
                              "resolved_condition_count": 0,
                              "scope": "observed_goldsky_primary_taker_fill",
                              "source_coverage": "partial_whale_threshold_fills",
                              "source_last_success_at": null,
                              "status": "degraded",
                              "taxonomy_version": "category-taxonomy-643",
                              "unresolved_observation_count": 0
                            },
                            {
                              "as_of": "2026-09-22T03:17:17.488299Z",
                              "brier_event_avg": null,
                              "canonical_category": "Tennis",
                              "edge_lower_95": null,
                              "edge_mean": null,
                              "edge_sd": null,
                              "edge_se": null,
                              "independent_event_count": 0,
                              "latest_observation_at": null,
                              "model_version": "category-skill-v2.0.0",
                              "observation_started_at": "2026-09-01T21:50:07.762477Z",
                              "platform": "polymarket",
                              "resolved_condition_count": 0,
                              "scope": "observed_goldsky_primary_taker_fill",
                              "source_coverage": "partial_whale_threshold_fills",
                              "source_last_success_at": null,
                              "status": "degraded",
                              "taxonomy_version": "category-taxonomy-643",
                              "unresolved_observation_count": 0
                            }
                          ],
                          "category_skill_model": {
                            "as_of": "2026-09-22T03:17:17.488299Z",
                            "model_version": "category-skill-v2.0.0",
                            "observation_started_at": "2026-09-01T21:50:07.762477Z",
                            "source_last_success_at": null,
                            "status": "degraded",
                            "taxonomy_version": "category-taxonomy-643"
                          },
                          "data_quality": {
                            "status": "partial",
                            "as_of": "2026-09-10T02:04:30.398422Z",
                            "field_groups": [
                              {
                                "group": "sync",
                                "owner": "traders.last_synced",
                                "status": "fresh",
                                "as_of": "2026-09-10T02:04:30.398422Z",
                                "max_age_s": 604800
                              },
                              {
                                "group": "sports_record",
                                "owner": "trader_product_scope_records.computed_at",
                                "status": "fresh",
                                "as_of": "2026-09-10T04:18:02.551204Z"
                              },
                              {
                                "group": "ranking",
                                "owner": "trader_rankings.computed_at",
                                "status": "fresh",
                                "as_of": "2026-09-10T06:12:44.120031Z",
                                "max_age_s": 604800
                              },
                              {
                                "group": "leaderboard_rank",
                                "owner": "leaderboard_rank_refresh_state.completed_at",
                                "status": "untracked",
                                "reason": "only S, A and B wallets are given a leaderboard rank"
                              },
                              {
                                "group": "volume",
                                "owner": "traders.last_synced",
                                "status": "fresh",
                                "as_of": "2026-09-10T02:04:30.398422Z",
                                "max_age_s": 604800
                              },
                              {
                                "group": "positions",
                                "owner": "trader_position_snapshots.last_refreshed_at|traders.last_synced",
                                "status": "unavailable",
                                "reason": "open-position unrealized P&L is unavailable for this wallet"
                              }
                            ]
                          },
                          "grade": "D",
                          "id": "trd_0xabc1230000000000000000000000000000000abc",
                          "last_active": "2026-09-09T21:47:12Z",
                          "pnl": {
                            "in_scope": {
                              "as_of": "2026-09-10T04:18:02.551204Z",
                              "basis": "polymarket_sports_esports_v1",
                              "markets": 412,
                              "markets_out_of_scope": 1477,
                              "markets_resolved": 398,
                              "realized_pnl": -1204.37,
                              "win_rate": 0.5812
                            }
                          },
                          "score": 40.17,
                          "stats": {
                            "markets_traded": 412,
                            "total_volume": 48210.55,
                            "win_rate": 0.5812
                          },
                          "strategy": {
                            "description": "Mixed activity across 1,802 stored markets. No single observed behavior has a clear lead. Category shares describe recorded USD cost basis; style is separate from performance.",
                            "strategy_type": "mixed"
                          },
                          "sync_status": "synced",
                          "synced_at": "2026-09-10T02:04:30.398422Z",
                          "username": "example_trader"
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "The address value names no trader: it is not a wallet address, and no username or trader ID this API knows matches it. error.code is not_found and error.param is address. A wallet address 0xinsider does not track yet is not an error; it returns 200 with sync_status \"unknown\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable, with two causes; branch on error.reason. (1) error.reason=read_model_warming: the position_summary read ran past its time budget twice on database pages that were not cached (it reads every position row the wallet has, so a wallet with a long history is the usual case). The pages those reads reached stay cached, so a retry after Retry-After (2 s) normally succeeds. The context is never served without its position_summary for this reason, and a partial breakdown is never served. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the per-process outage cooldown. Both carry error.code=rate_limit_unavailable.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a retry is worth making: 2 for read_model_warming, the rate limiter's outage cooldown otherwise.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/trader/{address}/context'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "trader_context",
            "data": {},
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/traders/batch": {
      "post": {
        "operationId": "batchGetTraders",
        "summary": "Batch traders",
        "description": "Returns traders for 1-25 wallet addresses or known usernames. Results preserve request order, duplicate inputs return duplicate rows, and each item is charged one batch item unit before execution. A wallet address this API does not track yet returns data with sync_status \"unknown\", matching the single trader endpoint. A username, trd_ id or numeric trader id that resolves to no trader is a per-item not_found error with error.param \"traders\", never an ok row keyed on the input.",
        "tags": ["Traders"],
        "requestBody": {
          "description": "Batch trader lookup request. Supply 1-25 wallet addresses, usernames, trd_-prefixed IDs, or integer trader IDs. Optional expand flags apply to every item.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["traders"],
                "properties": {
                  "traders": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 25,
                    "description": "Trader identities to resolve in input order.",
                    "items": {
                      "type": "string"
                    }
                  },
                  "expand": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": ["strategy", "categories", "quant_metrics", "trust"]
                    },
                    "description": "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."
                  }
                }
              },
              "example": {
                "traders": ["swisstony", "0x0000000000000000000000000000000000000000"],
                "expand": ["strategy"]
              }
            }
          }
        },
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ordered batch trader results",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Request-Cost": {
                "schema": {
                  "type": "integer"
                },
                "description": "Number of batch item units charged for this request."
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Batch-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Batch item units allowed per minute."
              },
              "X-Batch-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                },
                "description": "Batch item units remaining in the current sliding window."
              },
              "X-Batch-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Unix timestamp when the batch item window resets."
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "trader_batch"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BatchTraderItem"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/BatchResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "trader_batch",
                      "data": [
                        {
                          "index": 0,
                          "input": "0xabc1230000000000000000000000000000000abc",
                          "status": "ok",
                          "data": {
                            "id": "trd_0xabc1230000000000000000000000000000000abc",
                            "address": "0xabc1230000000000000000000000000000000abc",
                            "username": "example_trader",
                            "grade": "D",
                            "score": 40.17,
                            "forecast_score": 46.2,
                            "forecast_evidence": 0.38,
                            "streak_tier": "neutral",
                            "pnl": {
                              "unrealized": 135.56,
                              "in_scope": {
                                "basis": "polymarket_sports_esports_v1",
                                "realized_pnl": -1204.37,
                                "markets": 412,
                                "markets_resolved": 398,
                                "win_rate": 0.5812,
                                "markets_out_of_scope": 1477,
                                "as_of": "2026-09-10T04:18:02.551204Z"
                              }
                            },
                            "stats": {
                              "markets_traded": 412,
                              "win_rate": 0.5812,
                              "total_volume": 48210.55
                            },
                            "last_active": "2026-09-09T21:47:12Z",
                            "synced_at": "2026-09-10T02:04:30.398422Z",
                            "sync_status": "synced",
                            "data_quality": {
                              "status": "partial",
                              "as_of": "2026-09-10T02:04:30.398422Z",
                              "field_groups": [
                                {
                                  "group": "sync",
                                  "owner": "traders.last_synced",
                                  "status": "fresh",
                                  "as_of": "2026-09-10T02:04:30.398422Z",
                                  "max_age_s": 604800
                                },
                                {
                                  "group": "sports_record",
                                  "owner": "trader_product_scope_records.computed_at",
                                  "status": "fresh",
                                  "as_of": "2026-09-10T04:18:02.551204Z"
                                },
                                {
                                  "group": "ranking",
                                  "owner": "trader_rankings.computed_at",
                                  "status": "fresh",
                                  "as_of": "2026-09-10T06:12:44.120031Z",
                                  "max_age_s": 604800
                                },
                                {
                                  "group": "leaderboard_rank",
                                  "owner": "leaderboard_rank_refresh_state.completed_at",
                                  "status": "untracked",
                                  "reason": "only S, A and B wallets are given a leaderboard rank"
                                },
                                {
                                  "group": "volume",
                                  "owner": "traders.last_synced",
                                  "status": "fresh",
                                  "as_of": "2026-09-10T02:04:30.398422Z",
                                  "max_age_s": 604800
                                },
                                {
                                  "group": "positions",
                                  "owner": "trader_position_snapshots.last_refreshed_at|traders.last_synced",
                                  "status": "unknown",
                                  "reason": "open-position unrealized P&L is served, but no successful position snapshot or sync clock is available"
                                }
                              ]
                            }
                          }
                        },
                        {
                          "index": 1,
                          "input": "0xdef4560000000000000000000000000000000def",
                          "status": "ok",
                          "data": {
                            "id": "trd_0xdef4560000000000000000000000000000000def",
                            "address": "0xdef4560000000000000000000000000000000def",
                            "pnl": {},
                            "stats": {},
                            "sync_status": "unknown",
                            "data_quality": {
                              "status": "unavailable",
                              "field_groups": [
                                {
                                  "group": "sync",
                                  "owner": "traders.last_synced",
                                  "status": "unavailable",
                                  "reason": "no traders row exists for this wallet; sync_status is the synthetic value \"unknown\""
                                },
                                {
                                  "group": "sports_record",
                                  "owner": "trader_product_scope_records.computed_at",
                                  "status": "unavailable",
                                  "reason": "no traders row exists for this wallet; sync_status is the synthetic value \"unknown\""
                                },
                                {
                                  "group": "ranking",
                                  "owner": "trader_rankings.computed_at",
                                  "status": "unavailable",
                                  "reason": "no traders row exists for this wallet; sync_status is the synthetic value \"unknown\""
                                },
                                {
                                  "group": "leaderboard_rank",
                                  "owner": "leaderboard_rank_refresh_state.completed_at",
                                  "status": "unavailable",
                                  "reason": "no traders row exists for this wallet; sync_status is the synthetic value \"unknown\""
                                },
                                {
                                  "group": "volume",
                                  "owner": "traders.last_synced",
                                  "status": "unavailable",
                                  "reason": "no traders row exists for this wallet; sync_status is the synthetic value \"unknown\""
                                },
                                {
                                  "group": "positions",
                                  "owner": "trader_position_snapshots.last_refreshed_at|traders.last_synced",
                                  "status": "unavailable",
                                  "reason": "no traders row exists for this wallet; sync_status is the synthetic value \"unknown\""
                                }
                              ]
                            }
                          }
                        }
                      ],
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "total_items": 2,
                        "successful_items": 2,
                        "failed_items": 0,
                        "request_cost": 2,
                        "rate_limit": {
                          "basis": "batch_items_per_minute",
                          "limit": 2500,
                          "remaining": 2492,
                          "reset": 1790047440
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "The request body is over 1048576 bytes. error.code is bad_request, error.reason is payload_too_large and error.param is body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "415": {
            "description": "The body was not sent as Content-Type: application/json. error.code is bad_request, error.reason is unsupported_media_type and error.param is content-type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -X POST \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"traders\":[\"swisstony\",\"0x0000000000000000000000000000000000000000\"],\"expand\":[\"strategy\"]}' \\\n  'https://api.0xinsider.com/api/v1/traders/batch'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "trader_batch",
            "data": {},
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/trader/{address}/position-timeline": {
      "get": {
        "operationId": "getPositionTimeline",
        "summary": "Get a trader's position timeline for one market",
        "description": "Returns every stored Polymarket fill for one tracked trader in one market, newest first, with outcome-specific running_amount and running_avg_price including all earlier stored fills before pagination. Fills come from the full fill ledger, the same rows the trade export serves, at any date (#33245; until then the timeline served only large fills from 2026-07-17). An empty list means no fill is stored for the wallet on that market. A pair with more than 20,000 fills before the requested page answers 404 with error.reason fill_history_too_large rather than partial running totals. tx_hash is null for a fill with no large-trade alert. The {address} segment accepts the same identity shapes as the plural alias: wallet, username, trd_-prefixed trader id, bare integer traders.id, or @username, resolved with precedence @username -> wallet -> trd_ -> integer -> username. A leading @ resolves the rest as a username only, which is how to reach an all-digit username that the integer rule reads as an id. Only warm-tier traders, the wallets we sync most often, are served; others return 404. The cumulative buy-weighted fill average is unchanged by sells. Split, merge, redemption and neg-risk activity are excluded; totals are not complete holdings or provider current-position avgPrice. Cursor-paginated; values stay stable across page sizes/cursors for unchanged source history.",
        "tags": ["Traders"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "Trader identity: 0x... wallet address, username, trd_-prefixed trader id, bare integer traders.id, or @username. Resolved with precedence @username -> wallet -> trd_ -> integer -> username (a leading @ forces a username lookup, for all-digit usernames); wallet matching is case-insensitive.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "condition_id",
            "in": "query",
            "required": true,
            "description": "Market condition_id. One timeline per (trader, market).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of timeline events to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Pagination cursor from previous response's next_cursor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Position timeline page",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PositionTimelineEvent"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total matching rows when the read model exposes a count; the key is absent when it does not."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [],
                      "has_more": false,
                      "total": 0,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. On this route a 404 has FOUR distinct causes; branch on error.reason. (1) error.reason=\"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), so we capture no timeline for them. This is TERMINAL -- there is no Retry-After and no error.retry_at, because neither retrying nor re-spelling the path will ever succeed. Stop requesting this wallet. (2) no error.reason: the trader id or address does not resolve at all. Both carry error.code=\"not_found\" (a FROZEN contract value), so error.reason is the discriminator -- and since this endpoint has singular and plural path spellings, \"I used the wrong URL\" is a plausible enough wrong guess that the distinction is worth branching on. (3) error.reason=\"market_out_of_scope\" (#27311): condition_id names a market outside sports and esports, which 0xinsider serves exclusively. This is terminal too: stop requesting this market. (4) error.reason=\"fill_history_too_large\" (#33245): the wallet and market are tracked, but the wallet has more than 20,000 stored fills on the market before the requested page, and the timeline sums every earlier fill into its running totals. Terminal: stop requesting this pair.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/trader/0x1111111111111111111111111111111111111111/position-timeline?condition_id=0x2222222222222222222222222222222222222222222222222222222222222222'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/trader/{address}/categories": {
      "get": {
        "operationId": "getTraderCategoryRecords",
        "summary": "Get trader category win records",
        "description": "Returns one wallet's win record in every canonical category it has a settled market in: wins, decided (wins plus losses) and the rate, per category, busiest category first. These are the same counts the Pick of the Day holder chips carry. The Esports record also carries games: the wallet's record in each esports title it has a settled market in (LoL, CS2, Dota 2, Valorant, ...), the same per-game record the holder chips and GET /api/v1/market/{condition_id}/holders name in category_win_rate_game, with the same counts, floor and status rule; the Esports row itself stays the whole bucket, which is what a chip falls back to when a game record is thin. Every record also carries scopes: the wallet's record in each part of the category it has a settled market in, an esports title, a soccer league (UEFA Champions League, LaLiga, Premier League, ...) or a registered league of another sport (NBA, NFL, ATP, ...), each named by scope_key and display_name with the same counts, floor and status rule, and the same names Pick of the Day and the holder chips print. The basis is every settled market at any position size, which is NOT the basis of category_strengths on GET /api/v1/trader/{address}?expand=categories: that breakdown keeps the 20 USD notional floor and the entry-price rule its ranks depend on, so the two legitimately differ, in both directions. Measured on production 2026-09-22 over the 122,497 wallet-category pairs with at least 20 decided markets on both bases: the floored rate was higher in 56.5% of pairs, lower in 34.5% and equal in 9.0%, median +0.6 points, p10 -4.6, p90 +9.8, and 14.0% of pairs differ by 10 points or more. Neither rate corrects the other. The difference is not only small positions: on a 1-in-250 wallet sample the same day, admitted markets won 56.6% while markets dropped by the notional floor alone won 45.2% and markets dropped by the entry-price rule alone won 48.7%. The two tables also run on different clocks, this one rebuilt daily and that breakdown updated incrementally, so a same-day read can differ on timing alone. A category, game or scope with fewer than min_decided_for_win_rate decided markets keeps its counts and returns win_rate null with status not_enough_data, so a caller can apply its own sample rule. A category the wallet has no settled market in is omitted entirely, and so is a game or a scope: an absent entry means no record, never a 0% record. A resolved trader with no settled market returns an empty records array (HTTP 200); an unknown address returns 404. Sports and esports only (#27311): records cover sports and esports categories only, so a wallet whose settled markets are all elsewhere returns an empty records array.",
        "tags": ["Traders"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "Wallet address (0x...), username, or trd_-prefixed trader id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "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 and scopes, and one that reaches Soccer returns the Soccer record with every league in scopes; a game or a league is not a filter of its own, so ask for its category and read games or scopes. 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).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Trader category win records",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "trader_category_records"
                    },
                    "data": {
                      "$ref": "#/components/schemas/TraderCategoryRecords"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "example": {
                  "object": "trader_category_records",
                  "data": {
                    "id": "trd_0xabc1230000000000000000000000000000000abc",
                    "address": "0xabc1230000000000000000000000000000000abc",
                    "basis": "settled_markets_all_sizes",
                    "min_decided_for_win_rate": 5,
                    "computed_at": "2026-09-21T09:17:51.010285Z",
                    "records": [
                      {
                        "category": "Soccer",
                        "wins": 402,
                        "decided": 742,
                        "win_rate": 0.5417,
                        "status": "measured"
                      },
                      {
                        "category": "Basketball",
                        "wins": 222,
                        "decided": 320,
                        "win_rate": 0.6937,
                        "status": "measured"
                      }
                    ]
                  },
                  "meta": {
                    "request_id": "req_example",
                    "cached": false,
                    "cost": 1
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/trader/{address}/pnl": {
      "get": {
        "operationId": "getTraderPnl",
        "summary": "Get trader P&L time series",
        "description": "Returns a trader's sports and esports daily P&L time series and pre-derived stats: entries (daily realized P&L and its running sum), period stats (all/90d/30d/7d), monthly aggregation, per-year totals, the drawdown series, series_status, and realized, which reconciles the days with the wallet's Sports P&L (pnl.in_scope.realized_pnl on GET /api/v1/trader/{address}): the days plus realized.undated_pnl equal it. A day's daily_change is the realized P&L of the wallet's sports and esports markets dated to that UTC day, the resolution day for a settled market, else the last trade day. series_status pending means the series is not computed yet; its empty sections never mean zero. A resolved trader with no sports or esports day returns an empty structured object (HTTP 200), as does a wallet that traded no sports or esports market (series_status ready, realized null, freshness_at its last completed sync; since 2026-10-29, #30589, #30657) or that trades only combos and holds no single sports or esports market (the same; since 2026-10-29, #30637); an unknown address returns 404. Optional from/to and sections bound what comes back: from/to clip the two daily series (entries, drawdown) to an inclusive UTC date window, and sections names which of the five sections the body carries. A request that sends none of the three receives the whole object and no data.view. A body built with any of them carries data.view, which names the bounds, the sections applied, the size of the full series and the last daily point before the window; a section the request excluded is absent from data, not null or empty. stats, monthly and year_totals keep their full-period definitions whatever the window says, so an economic value never changes meaning because a chart asked for seven days.",
        "tags": ["Traders"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "Wallet address (0x...), username, or trd_-prefixed trader id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Inclusive UTC calendar-date lower bound in YYYY-MM-DD form for the daily series (entries and drawdown). Omit for the whole stored history. A value that is not a calendar date, or a from later than to, returns 400 bad_request with error.param from. Does not change stats, monthly or year_totals, which stay defined over the full history.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Inclusive UTC calendar-date upper bound in YYYY-MM-DD form for the daily series (entries and drawdown). Omit for the whole stored history. A value that is not a calendar date returns 400 bad_request with error.param to. Does not change stats, monthly or year_totals.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "sections",
            "in": "query",
            "required": false,
            "description": "Which sections of the object to return. Repeatable and comma-separated: entries, stats, monthly, year_totals, drawdown. Omit it, or send it empty, for all five. A section left out is absent from data. An unrecognized name returns 400 bad_request with error.param sections rather than being ignored, so a typo cannot look like a successful request that silently dropped the section you came for.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["entries", "stats", "monthly", "year_totals", "drawdown"]
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "sections[]",
            "in": "query",
            "required": false,
            "description": "Backward-compatible bracket alias for sections, for clients that emit array keys. Repeatable and comma-separated: entries, stats, monthly, year_totals, drawdown.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["entries", "stats", "monthly", "year_totals", "drawdown"]
              }
            },
            "style": "form",
            "explode": true
          }
        ],
        "responses": {
          "200": {
            "description": "Trader P&L object",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "trader_pnl"
                    },
                    "data": {
                      "$ref": "#/components/schemas/TraderPnl"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "example": {
                  "object": "trader_pnl",
                  "data": {
                    "id": "trd_0xabc123",
                    "freshness_at": "2026-05-12T18:04:11Z",
                    "series_status": "ready",
                    "realized": {
                      "basis": "polymarket_sports_esports_v1",
                      "realized_pnl": 51240.5,
                      "dated_pnl": 50000,
                      "undated_pnl": 1240.5
                    },
                    "entries": [
                      {
                        "date": "2026-05-12",
                        "markets_traded": 3,
                        "total_volume": 10000,
                        "cumulative_profit": 50000,
                        "total_pnl": 50000,
                        "daily_change": 250
                      }
                    ],
                    "stats": {
                      "all": {
                        "current": 50000,
                        "change": 50000,
                        "change_pct": 0,
                        "best_day": 5000,
                        "worst_day": -2000,
                        "win_days": 30,
                        "loss_days": 10,
                        "avg_day": 250,
                        "rebase_anchor": 0
                      },
                      "d90": {
                        "current": 12000,
                        "change": 12000,
                        "change_pct": 31.5,
                        "best_day": 5000,
                        "worst_day": -2000,
                        "win_days": 18,
                        "loss_days": 6,
                        "avg_day": 500,
                        "rebase_anchor": 38000
                      },
                      "d30": {
                        "current": 4000,
                        "change": 4000,
                        "change_pct": 8.7,
                        "best_day": 2500,
                        "worst_day": -800,
                        "win_days": 9,
                        "loss_days": 3,
                        "avg_day": 333,
                        "rebase_anchor": 46000
                      },
                      "d7": {
                        "current": 900,
                        "change": 900,
                        "change_pct": 1.8,
                        "best_day": 600,
                        "worst_day": -150,
                        "win_days": 4,
                        "loss_days": 1,
                        "avg_day": 180,
                        "rebase_anchor": 49100
                      }
                    },
                    "monthly": [
                      {
                        "year": 2026,
                        "month": 5,
                        "pnl": 12000,
                        "markets_traded": 18
                      }
                    ],
                    "year_totals": [
                      {
                        "year": 2026,
                        "pnl": 50000
                      }
                    ],
                    "drawdown": [
                      {
                        "date": "2026-05-12",
                        "cumulative_profit": 50000,
                        "drawdown": -1500
                      }
                    ]
                  },
                  "meta": {
                    "request_id": "req_example",
                    "cached": false,
                    "cost": 1
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/trader/0xabc123/pnl'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/traders/{trader}/position-timeline": {
      "get": {
        "operationId": "getPositionTimelineById",
        "summary": "Get a trader's position timeline (unified identity resolver)",
        "description": "Unified trader-timeline route (#4975). {trader} accepts all five identity shapes - 0x... wallet, username, trd_-prefixed trader id, bare integer id, and @username (a username lookup only, for all-digit usernames) - resolved by the single shared trader-identity resolver. Returns every stored Polymarket fill for one tracked trader in one market, newest first, with server-computed running_amount and running_avg_price, from the full fill ledger at any date (#33245). A pair with more than 20,000 fills before the requested page answers 404 with error.reason fill_history_too_large. Only warm-tier traders, the wallets we sync most often, are tracked; other traders return 404. Response payload matches the singular GET /api/v1/trader/{address}/position-timeline route for the same (trader, market), except for the per-request meta.request_id. The prior integer-id-only variant is preserved: the same path now accepts every identity shape.",
        "tags": ["Traders"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "trader",
            "in": "path",
            "required": true,
            "description": "Trader identity: 0x... wallet address, username, trd_-prefixed trader id, bare integer traders.id, or @username. Resolved with precedence @username -> wallet -> trd_ -> integer -> username (a leading @ forces a username lookup, for all-digit usernames). Unknown identities return 404.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "condition_id",
            "in": "query",
            "required": true,
            "description": "Market condition_id. One timeline per (trader, market).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of timeline events to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Pagination cursor from previous response's next_cursor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Position timeline page",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PositionTimelineEvent"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total matching rows when the read model exposes a count; the key is absent when it does not."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [],
                      "has_more": false,
                      "total": 0,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. On this route a 404 has FOUR distinct causes; branch on error.reason. (1) error.reason=\"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), so we capture no timeline for them. This is TERMINAL -- there is no Retry-After and no error.retry_at, because neither retrying nor re-spelling the path will ever succeed. Stop requesting this wallet. (2) no error.reason: the trader id or address does not resolve at all. Both carry error.code=\"not_found\" (a FROZEN contract value), so error.reason is the discriminator -- and since this endpoint has singular and plural path spellings, \"I used the wrong URL\" is a plausible enough wrong guess that the distinction is worth branching on. (3) error.reason=\"market_out_of_scope\" (#27311): condition_id names a market outside sports and esports, which 0xinsider serves exclusively. This is terminal too: stop requesting this market. (4) error.reason=\"fill_history_too_large\" (#33245): the wallet and market are tracked, but the wallet has more than 20,000 stored fills on the market before the requested page, and the timeline sums every earlier fill into its running totals. Terminal: stop requesting this pair.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/traders/trd_123/position-timeline?condition_id=0x2222222222222222222222222222222222222222222222222222222222222222'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/props": {
      "get": {
        "operationId": "listProps",
        "summary": "List player props across a league",
        "description": "Player props for the catalog's games of one league, one row per market, ordered by game slug, stat, player and line. NFL files props on a game's -player-props and -first-td-scorer child events and NBA on the game event; this reads both, so a caller does not walk GET /api/v1/games and then each game's markets. Every field is the stored provider fact but player: stat is the provider sportsMarketType, line its typed line (null on a yes/no prop such as an anytime touchdown), title and group_item_title the question and group label, and outcomes both outcome labels with their CLOB token ids. player.name is the group label before its first \": \" (the question's, for a goalscorer family), or the whole label when it has none, the rule the event page's Player props section uses; when the provider stored no title, player is null and player_unavailable_reason is missing_provider_title. Each row also names its game: game_event_slug, starts_at and competitors. Polymarket does not publish which team a player is on. Settlement payouts stay on GET /api/v1/games/{event_slug}/markets. expand=quotes adds each outcome's quote, the object GET /api/v1/games/{event_slug}/markets returns: the cached display price with its basis and observation time, the cached best bid and ask, and book_depth_within_2c. The board opens no live book: it reads the league's unstreamed books from CLOB behind the response, so a prop with no book yet reads book_unavailable_reason cache_miss (read again in a few seconds), and cache_unavailable when we could not read the book from the cache; book_source names who read the book (clob_stream or clob_rest), and a price no cache holds is fetched behind the response for the next read. max_spread_c keeps only props with an outcome whose cached spread is at most that many cents; min_book_usd_within_2c keeps only props with an outcome whose cached book holds at least that many USD on each side within 2 cents of its midpoint (the quote's book_depth_within_2c); with both, one outcome must meet both. They read the same cached books and leave out a prop whose book, or depth for min_book_usd_within_2c, is not cached yet, counting it on coverage.rows_without_book (null without either filter). A cursor never revisits a prop a page passed over, whether its book was wider or not cached yet, so when coverage.rows_without_book is above 0, read from the first page again after a few seconds to judge those props; the board reads books for active props only, so a closed prop, or one whose outcome has no provider token id yet, stays unjudged. When the book cache cannot be read for the first prop a page must judge, the read answers 503 with error.reason read_model_warming and Retry-After, not an empty page that repeats its cursor. Cost is 2, plus 1 with quotes. A page can hold fewer than limit rows, or none, while has_more is true: a read that has not filled its page stops after about 100 ms of prop reads (a player filter that matches few rows) and resumes on the next page, and a child event out of scope is dropped. Follow next_cursor while has_more is true. An unknown league is 400 invalid_query. A known league with no games in the window is an empty page. coverage.sources_unavailable names each game catalog scope half that could carry the league's games and did not answer for this read, as <sport>:<half> (the entries GET /api/v1/games publishes on its coverage); while one is listed the page can be missing that half's games.",
        "tags": ["Games"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "league",
            "in": "query",
            "required": true,
            "description": "League tag as GET /api/v1/games coverage.leagues spells it, for example nfl or nba. Matched case-insensitively.",
            "schema": {
              "type": "string",
              "maxLength": 32
            }
          },
          {
            "name": "starts_after",
            "in": "query",
            "required": false,
            "description": "RFC 3339 kickoff bound. A game with no published kickoff is excluded whenever either bound is set.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "starts_before",
            "in": "query",
            "required": false,
            "description": "RFC 3339 kickoff bound, inclusive.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "player",
            "in": "query",
            "required": false,
            "description": "Part of player.name, ignoring case and accents: jokic matches Nikola Jokić. A row with no player does not match.",
            "schema": {
              "type": "string",
              "maxLength": 80
            }
          },
          {
            "name": "stat",
            "in": "query",
            "required": false,
            "description": "Provider sportsMarketType values to keep, case-insensitive, for example passing_yards or points. Repeat the parameter or send a comma-separated list. An unknown type returns an empty page.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "stat[]",
            "in": "query",
            "required": false,
            "description": "Bracket alias for stat, as expand[] is for expand. Repeatable; same values.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "active (default), closed, or all. closed means the provider closed the market or it resolved.",
            "schema": {
              "type": "string",
              "enum": ["active", "closed", "all"],
              "default": "active"
            }
          },
          {
            "name": "max_spread_c",
            "in": "query",
            "required": false,
            "description": "Keep only props with an outcome whose cached best ask less best bid is at most this many cents: above 0, at most 100, in steps of 0.01. The books are the ones expand=quotes serves, read from the cache with no request-path CLOB call. A prop whose book is not cached yet is left out of data and counted on coverage.rows_without_book; the board reads its league's books behind the response, so a read a few seconds later can judge it. A cursor never revisits a prop a page passed over, whether its book was wider or not cached yet, so when coverage.rows_without_book is above 0, read from the first page again after a few seconds to judge those props; the board reads books for active props only, so a closed prop, or one whose outcome has no provider token id yet, stays unjudged. When the book cache cannot be read for the first prop a page must judge, the read answers 503 with error.reason read_model_warming and Retry-After, not an empty page that repeats its cursor.",
            "schema": {
              "type": "number",
              "exclusiveMinimum": 0,
              "maximum": 100,
              "multipleOf": 0.01
            },
            "example": 2
          },
          {
            "name": "min_book_usd_within_2c",
            "in": "query",
            "required": false,
            "description": "Keep only props with an outcome whose cached book holds at least this many USD on each side within 2 cents of its midpoint: bids at or above the midpoint minus 0.02 and asks at or below the midpoint plus 0.02, each level's price times size, from the whole book. A whole number from 1 to 10000000, the measure the market_price_moved webhook filter of the same name uses; expand=quotes serves the two sums as book_depth_within_2c. With max_spread_c, one outcome must meet both. The books are read from the cache with no request-path CLOB call. A prop whose book or depth is not cached yet is left out of data and counted on coverage.rows_without_book; the board reads its league's books behind the response, so a read a few seconds later can judge it. A cursor never revisits a prop a page passed over, so when coverage.rows_without_book is above 0, read from the first page again after a few seconds to judge those props; the board reads books for active props only, so a closed prop, or one whose outcome has no provider token id yet, stays unjudged. When the book cache cannot be read for the first prop a page must judge, the read answers 503 with error.reason read_model_warming and Retry-After, not an empty page that repeats its cursor.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10000000
            },
            "example": 500
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. Out-of-range values are clamped to 1..200.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque prp_v1_ cursor from next_cursor, sent with the same filters. A cursor this endpoint did not issue returns 400 with error.param=cursor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand",
            "in": "query",
            "required": false,
            "description": "quotes adds each outcome's cached quote, as on GET /api/v1/games/{event_slug}/markets; it adds 1 to the cost, on every plan. Repeatable: quotes.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["quotes"]
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "expand[]",
            "in": "query",
            "required": false,
            "description": "Backward-compatible alias for expand. Repeatable: quotes.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["quotes"]
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET using a weak semantic ETag from an earlier response. A matching payload returns 304 with an empty body; request_id and cost are excluded from the validator.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/props?league=nfl&stat=passing_yards&expand=quotes'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "responses": {
          "200": {
            "description": "One page of player props",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "as_of": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "id",
                          "condition_id",
                          "event_slug",
                          "league",
                          "competitors",
                          "player",
                          "stat",
                          "outcomes",
                          "status",
                          "game_event_slug",
                          "starts_at",
                          "player_unavailable_reason",
                          "line",
                          "title",
                          "group_item_title",
                          "resolved_at"
                        ],
                        "properties": {
                          "competitors": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "condition_id": {
                            "type": "string"
                          },
                          "event_slug": {
                            "type": "string"
                          },
                          "id": {
                            "type": "string"
                          },
                          "league": {
                            "type": "string"
                          },
                          "line": {
                            "type": ["number", "null"]
                          },
                          "outcomes": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "required": ["index"],
                              "properties": {
                                "index": {
                                  "type": "integer"
                                },
                                "label": {
                                  "type": "string"
                                },
                                "token_id": {
                                  "type": "string"
                                },
                                "quote": {
                                  "type": "object",
                                  "required": [
                                    "status",
                                    "price",
                                    "price_basis",
                                    "price_observed_at",
                                    "best_bid",
                                    "best_ask",
                                    "book_observed_at",
                                    "book_unavailable_reason",
                                    "book_source",
                                    "book_depth_within_2c"
                                  ],
                                  "properties": {
                                    "best_ask": {
                                      "type": ["number", "null"]
                                    },
                                    "best_bid": {
                                      "type": ["number", "null"]
                                    },
                                    "book_observed_at": {
                                      "type": ["string", "null"],
                                      "format": "date-time"
                                    },
                                    "book_unavailable_reason": {
                                      "anyOf": [
                                        {
                                          "type": "string",
                                          "enum": [
                                            "cache_miss",
                                            "stream_capacity",
                                            "not_streamed",
                                            "no_orderbook",
                                            "missing_provider_token_id",
                                            "cache_unavailable"
                                          ]
                                        },
                                        {
                                          "type": "null"
                                        }
                                      ]
                                    },
                                    "price": {
                                      "type": ["number", "null"]
                                    },
                                    "price_basis": {
                                      "anyOf": [
                                        {
                                          "type": "string",
                                          "enum": ["midpoint", "last_trade"]
                                        },
                                        {
                                          "type": "null"
                                        }
                                      ]
                                    },
                                    "price_observed_at": {
                                      "type": ["string", "null"],
                                      "format": "date-time"
                                    },
                                    "status": {
                                      "type": "string",
                                      "enum": ["observed", "no_orderbook", "unavailable"]
                                    },
                                    "book_source": {
                                      "anyOf": [
                                        {
                                          "type": "string",
                                          "enum": ["clob_stream", "clob_rest"]
                                        },
                                        {
                                          "type": "null"
                                        }
                                      ]
                                    },
                                    "book_depth_within_2c": {
                                      "anyOf": [
                                        {
                                          "type": "object",
                                          "required": ["bid_usd", "ask_usd"],
                                          "properties": {
                                            "ask_usd": {
                                              "type": "number"
                                            },
                                            "bid_usd": {
                                              "type": "number"
                                            }
                                          }
                                        },
                                        {
                                          "type": "null"
                                        }
                                      ]
                                    }
                                  }
                                }
                              }
                            }
                          },
                          "player": {
                            "type": ["object", "null"],
                            "required": ["name"],
                            "properties": {
                              "name": {
                                "type": "string"
                              }
                            }
                          },
                          "starts_at": {
                            "type": ["string", "null"],
                            "format": "date-time"
                          },
                          "stat": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string"
                          },
                          "title": {
                            "type": ["string", "null"]
                          },
                          "game_event_slug": {
                            "type": "string"
                          },
                          "group_item_title": {
                            "type": ["string", "null"]
                          },
                          "player_unavailable_reason": {
                            "anyOf": [
                              {
                                "type": "string",
                                "enum": ["missing_provider_title"]
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "resolved_at": {
                            "type": ["string", "null"],
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "league": {
                      "type": "string"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "object": {
                      "type": "string"
                    },
                    "coverage": {
                      "type": "object",
                      "required": ["sources_unavailable", "rows_without_book"],
                      "properties": {
                        "sources_unavailable": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "rows_without_book": {
                          "type": ["integer", "null"]
                        }
                      }
                    }
                  },
                  "required": ["object", "league", "data", "has_more", "as_of", "meta", "coverage"]
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Bad request. error.param names the parameter: league missing, over 32 characters, not letters, digits, hyphens and underscores, or not one GET /api/v1/games lists on coverage.leagues; starts_after or starts_before not an RFC 3339 timestamp, or starts_after later than starts_before; player over 80 characters; stat over 512 characters in all; status other than active, closed or all; limit that is not an integer; a stat or expand value with broken percent-encoding; or a cursor this endpoint did not issue. An unknown expand value is ignored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Temporarily unavailable. error.reason=database_unavailable means the props read could not reach the database; retry after Retry-After. error.reason=read_model_warming means a max_spread_c or min_book_usd_within_2c read could not read the first book it had to judge from the cache; retry after Retry-After. The authenticated rate limiter being unavailable answers the same status with its own per-process cooldown.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/positions": {
      "get": {
        "operationId": "listPositions",
        "summary": "List current positions (positions-board feed)",
        "x-snapshot-consistency": "With consistency=snapshot and at least one wallet, the server freezes at most 500 matching rows and 2 MB of position data for up to five minutes. One snapshot per API key is retained; a new first-page snapshot replaces the prior one. A missing, replaced, or expired snapshot returns cursor_expired and the client starts at page one. Snapshot consistency does not imply complete provider coverage.",
        "description": "Returns the current positions-board feed backed by the wallet_positions mirror. Ordered by current_value_usd DESC with deterministic (wallet, condition_id, outcome_index) tiebreakers. Pre-reconcile rows (current_value_usd IS NULL) are excluded. Positions on resolved markets are excluded: a position leaves the feed when its market resolves, so a condition_id read of a resolved market returns no rows. Positions on markets outside sports and esports are excluded on every read, the board and wallet reads included. Cursor-paginated. Every filter pushes into SQL. Deep cursor pages cost the same as the first page: the value bounds and the cursor are index conditions, so a page never rescans the feed from the top. With wallet, the same feed is read for one wallet or a book of up to 25 wallets from each wallet's own ordered index range, so the pages are that wallet's complete reconciled binary open positions on sports and esports markets and the cost is the page, never the board. min_size defaults to 100 on the board read, so a request with no wallet and no min_size drops positions valued under 100 USD; with wallet it defaults to 0 instead. Send min_size=0 to include every reconciled position. What a wallet read does not return: positions with shares at 0 (closed), positions on resolved markets (redeemable or already redeemed), positions on markets outside sports and esports, rows the reconciler has not valued yet (current_value_usd IS NULL), and non-binary outcomes; per-row last_reconciled_at and freshness say how old each valuation is. Each row also carries additive `exact` source atoms as decimal strings with unit, scale and basis metadata; parse those values with decimal-safe arithmetic and do not reconstruct them from the display-safe numeric fields. The response adds a top-level `data_quality` object beside `data`, with positions, trader, and market groups owned by `wallet_positions.last_reconciled_at|updated_at`, `traders.last_synced`, and `market_canonical.last_refreshed_at`. Its stored clocks are part of the ETag; `meta` continues to hold transport cache facts.",
        "tags": ["Positions"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of current positions to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Pagination cursor from previous response's next_cursor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "consistency",
            "in": "query",
            "description": "live (default) reads the current value-ordered board. snapshot requires wallet and freezes up to 500 matching rows and 2 MB for up to five minutes. Keep consistency=snapshot and the same effective filters on every page; changing filters returns 400. A new first page from the same API key replaces its prior snapshot; replacement or expiry returns cursor_expired.",
            "schema": {
              "type": "string",
              "enum": ["live", "snapshot"],
              "default": "live"
            }
          },
          {
            "name": "min_size",
            "in": "query",
            "description": "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.",
            "schema": {
              "type": "number",
              "default": 100
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "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).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "condition_id",
            "in": "query",
            "description": "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.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "wallet",
            "in": "query",
            "required": false,
            "description": "Scope to one wallet or a book of wallets (repeatable, up to 25 per request; comma-separated values inside one occurrence also work). Each value is a wallet address, a known username, or a trd_-prefixed trader id, resolved like /api/v1/trader/{address}. The response keeps the board's order and cursor, so pages of a book interleave wallets by current_value_usd. An address this API has never tracked returns its mirror rows or an empty list; a username or trader id that resolves to nothing is a 404 naming wallet; more than 25 values is a 400. min_size defaults to 0 when wallet is present.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "maxItems": 25
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "wallet[]",
            "in": "query",
            "required": false,
            "description": "Backward-compatible bracket alias for wallet. Repeatable; same values and limits.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "maxItems": 25
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "min_grade",
            "in": "query",
            "description": "Minimum trader grade allowlist. `A` matches S and A; `B` matches S, A, B; etc.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"]
            }
          },
          {
            "name": "side",
            "in": "query",
            "description": "Filter by the binary outcome side. `yes` maps to outcome_index=0, `no` to outcome_index=1.",
            "schema": {
              "type": "string",
              "enum": ["yes", "no"]
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of positions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "data_quality", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Position"
                      }
                    },
                    "data_quality": {
                      "$ref": "#/components/schemas/DataQuality",
                      "description": "Writer-backed age and coverage for this page; it is part of the representation and the ETag, while transport cache facts remain in meta."
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total matching rows when the read model exposes a count; the key is absent when it does not."
                    },
                    "snapshot": {
                      "type": "object",
                      "description": "Present only with consistency=snapshot. Dates the frozen response rows, not the provider's underlying observations.",
                      "required": ["as_of", "expires_at", "row_count"],
                      "properties": {
                        "as_of": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "expires_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "row_count": {
                          "type": "integer"
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [],
                      "data_quality": {
                        "status": "partial",
                        "field_groups": [
                          {
                            "group": "positions",
                            "owner": "wallet_positions.last_reconciled_at|updated_at",
                            "status": "unknown",
                            "reason": "the page returned no served position rows from which to read this writer clock"
                          },
                          {
                            "group": "trader",
                            "owner": "traders.last_synced",
                            "status": "unknown",
                            "reason": "the page returned no served position rows from which to read this writer clock"
                          },
                          {
                            "group": "market",
                            "owner": "market_canonical.last_refreshed_at",
                            "status": "unknown",
                            "reason": "the page returned no served position rows from which to read this writer clock"
                          }
                        ]
                      },
                      "has_more": false,
                      "total": 0,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "A wallet value that resolves to no trader: a username or trd_-prefixed trader ID with no match. error.param is wallet. An address 0xinsider does not track is not an error; it returns the rows stored for it, or an empty list. error.reason=\"market_out_of_scope\" (#27311): condition_id names a market outside sports and esports, which 0xinsider serves exclusively; stop requesting it. Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/positions'"
          },
          {
            "lang": "curl",
            "label": "cURL (one market, every size)",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/positions?condition_id=0x...&min_size=0&limit=100'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "data_quality": {
              "status": "partial",
              "field_groups": [
                {
                  "group": "positions",
                  "owner": "wallet_positions.last_reconciled_at|updated_at",
                  "status": "unknown",
                  "reason": "the page returned no served position rows from which to read this writer clock"
                },
                {
                  "group": "trader",
                  "owner": "traders.last_synced",
                  "status": "unknown",
                  "reason": "the page returned no served position rows from which to read this writer clock"
                },
                {
                  "group": "market",
                  "owner": "market_canonical.last_refreshed_at",
                  "status": "unknown",
                  "reason": "the page returned no served position rows from which to read this writer clock"
                }
              ]
            },
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/large-positions": {
      "get": {
        "operationId": "listLargePositions",
        "summary": "List large positions",
        "description": "Returns the largest current open positions from graded traders, value-descending, with opaque cursor pagination. This is a change-detection feed, not a holder list: a row needs a current value of at least 50,000 USD and a live detection in the last 24 hours, so a wallet that holds a market without moving is not listed. For every graded holder of one market use GET /api/v1/market/{condition_id}/holders. Polymarket-only by design: the large-positions scanner filters platform = 'polymarket' (backend/crates/large-positions/src/scanner.rs), so only Polymarket rows are scanned and an unknown condition_id filter returns an empty list (never fabricated rows). Sports and esports markets only (#27305): a position on a market outside product scope is not listed; a condition_id naming one returns 404 not_found with error.reason=market_out_of_scope, and a category outside sports and esports returns 400 bad_request with param=category. The teaser cap that the internal product UI applies to anonymous viewers does not apply here: the API key already proves an active Pro subscription (wire tier `insider`), so authed API callers get full access.",
        "tags": ["Large Positions"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of large positions to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor from a previous response.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_size",
            "in": "query",
            "description": "Minimum position value in USD. Raises the feed's own floor of 50,000 USD; a smaller value does not lower it.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "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).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_grade",
            "in": "query",
            "description": "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.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"]
            }
          },
          {
            "name": "condition_id",
            "in": "query",
            "description": "Scope to one market. Accepts the raw provider condition_id or the mkt_-prefixed market id (round-trips a value from a list response). Must be 0x followed by 64 hexadecimal characters after any mkt_ prefix is stripped; any other value returns 400. Polymarket-only; an unknown but well-formed id returns []. A market outside sports and esports returns 404 not_found with error.reason=market_out_of_scope (#27305).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Large positions list",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LargePosition"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page; absent on the last page."
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total ranked rows when the read model exposes a count; may be absent."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [],
                      "has_more": false,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27305): condition_id names a real market outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this market. It carries error.code=\"not_found\". An unknown but well-formed condition_id is not a 404: it returns [].",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/large-positions?min_grade=A&limit=10'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/large-trades": {
      "get": {
        "operationId": "listLargeTrades",
        "summary": "List large trades",
        "description": "Returns recent large trades with signal scoring and persisted suspicion facts. Filter by size, category, trader grade, or persisted suspicion. Filters are applied before pagination, and every request uses SQL-backed limit + 1 pagination so has_more and next_cursor reflect the filtered result set. Cursor-paginated, newest first. Market categories come from provider-backed market_canonical identity. Returns trades on sports and esports markets only (#27430): a trade on any other market is not listed, not counted toward has_more, and not returned by since. The response adds a top-level `data_quality` object beside `data`, grouping alert, trade, trader, ranking, market, and volume fields by their database writer. `whale_alerts.inserted_xid` is reported as unknown because it is a transaction identifier rather than a timestamp. Its stored clocks are part of the ETag; `meta` continues to hold transport cache facts. Pass since to poll for new trades: the answer holds only the trades recorded after the one you name, and with If-None-Match a poll that finds none is 304 with an empty body.",
        "tags": ["Large trades"],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of recent large trades to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Pagination cursor from previous response's next_cursor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_size",
            "in": "query",
            "description": "Minimum trade size in USD.",
            "schema": {
              "type": "number",
              "default": 5000
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "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).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_grade",
            "in": "query",
            "description": "Minimum trader grade now (trader.grade), the wallet's grade when this page is read, not when the trade filled. A wallet re-graded after a trade enters or leaves the result, so a catch-up read can disagree with GET /api/v1/stream and webhooks. For the grade at the fill, send min_grade_at_trade instead. A means S or A, B means S, A or B.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"]
            }
          },
          {
            "name": "min_grade_at_trade",
            "in": "query",
            "description": "Minimum grade the trader held when the trade filled (trader.grade_at_trade). Only rows whose trader.grade_at_trade_status is graded can match, so a trade before 2026-09-19T23:00Z, or one made while the wallet's grade was changing, never does. The same basis as min_grade_at_trade on GET /api/v1/stream and on webhook trade_filters, so a client that catches up here and then streams gets one answer. Applies to every path: recent, since, sort=market_volume_share, condition_id and event_slug. Sending it with min_grade is 400. A means S or A, B means S, A or B.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"]
            }
          },
          {
            "name": "suspicious_only",
            "in": "query",
            "description": "When true, return only rows with persisted suspicion_score >= 60. The filter is applied before SQL-backed limit + 1 pagination.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "min_market_volume_share",
            "in": "query",
            "description": "Keep only trades whose market_volume_share is known and at least this. A fraction, not a percent: 0.01 is one percent of the market's traded volume. A trade whose share is unavailable is never returned by a non-zero value, because an unavailable share cannot be said to clear a floor.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Order of the returned page. recent is newest first and is the default. market_volume_share ranks by each trade's share of its market's traded volume, biggest first, with a trade whose share is unavailable last. That ranking reads the last 30 days, because the share is computed for each request and an unbounded ranking cannot be served inside the documented latency budget. A cursor is bound to the order it was minted in, so a continuation cannot cross from one order into the other.",
            "schema": {
              "type": "string",
              "enum": ["recent", "market_volume_share"],
              "default": "recent"
            }
          },
          {
            "name": "since",
            "in": "query",
            "description": "Return only the trades recorded after this one. Pass the id of a large trade this API returned (wt_<n>, or the bare integer). The answer keeps the list shape and newest-first order, and next_cursor pages within it. After means commit order: a trade recorded late with an earlier traded_at is still returned, and a trade whose write has not committed yet is returned on a later poll, never skipped. To poll, send the id of the first trade on the first page of your last answer that had trades, with If-None-Match set to the ETag you last received; when nothing new was recorded the answer is 304 with an empty body. A late trade can come back once, so deduplicate on id. Only with sort=recent. An id that names no trade, or one more than 10000 trades behind the newest, answers 400 with error.param since; request the list without since and continue from its first trade.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "condition_id",
            "in": "query",
            "description": "Only this market's large trades: an exact raw provider condition_id. The page is read from the market's own index, newest first, and pages with cursor; it cannot be combined with since or with event_slug (400). An unknown market returns an empty list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "event_slug",
            "in": "query",
            "description": "Only the large trades in one game: every market of the game behind this event slug, the moneyline, spreads, totals and props, as GET /api/v1/games/{event_slug}/trades reads them. Matched case-insensitively. Newest first only (sort=market_volume_share answers 400), pages with cursor, and cannot be combined with since or with condition_id (400). An unknown slug answers 404 not_found with error.param event_slug.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of large trades",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "data_quality", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LargeTrade"
                      }
                    },
                    "data_quality": {
                      "$ref": "#/components/schemas/DataQuality",
                      "description": "Writer-backed age and coverage for this page; it is part of the representation and the ETag, while transport cache facts remain in meta."
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total matching rows when the read model exposes a count; absent (or null) when it does not."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [],
                      "data_quality": {
                        "status": "partial",
                        "field_groups": [
                          {
                            "group": "alert",
                            "owner": "whale_alerts.inserted_xid",
                            "status": "unknown",
                            "reason": "whale_alerts.inserted_xid is a transaction identifier rather than a timestamp"
                          },
                          {
                            "group": "trade",
                            "owner": "trades.ingested_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "trader",
                            "owner": "traders.last_synced",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "ranking",
                            "owner": "trader_rankings.computed_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "market",
                            "owner": "market_canonical.last_refreshed_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "volume",
                            "owner": "market_live_stats.volume_request_observed_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          }
                        ]
                      },
                      "has_more": false,
                      "total": 0,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/large-trades'"
          },
          {
            "lang": "curl",
            "label": "cURL (poll for new trades)",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  -H \"If-None-Match: $LAST_ETAG\" \\\n  \"https://api.0xinsider.com/api/v1/large-trades?since=$NEWEST_TRADE_ID\""
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "data_quality": {
              "status": "partial",
              "field_groups": [
                {
                  "group": "alert",
                  "owner": "whale_alerts.inserted_xid",
                  "status": "unknown",
                  "reason": "whale_alerts.inserted_xid is a transaction identifier rather than a timestamp"
                },
                {
                  "group": "trade",
                  "owner": "trades.ingested_at",
                  "status": "unknown",
                  "reason": "the page returned no large-trade row from which to read this writer clock"
                },
                {
                  "group": "trader",
                  "owner": "traders.last_synced",
                  "status": "unknown",
                  "reason": "the page returned no large-trade row from which to read this writer clock"
                },
                {
                  "group": "ranking",
                  "owner": "trader_rankings.computed_at",
                  "status": "unknown",
                  "reason": "the page returned no large-trade row from which to read this writer clock"
                },
                {
                  "group": "market",
                  "owner": "market_canonical.last_refreshed_at",
                  "status": "unknown",
                  "reason": "the page returned no large-trade row from which to read this writer clock"
                },
                {
                  "group": "volume",
                  "owner": "market_live_stats.volume_request_observed_at",
                  "status": "unknown",
                  "reason": "the page returned no large-trade row from which to read this writer clock"
                }
              ]
            },
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/whale-trades": {
      "get": {
        "operationId": "listWhaleTrades",
        "summary": "List whale trades",
        "description": "Returns recent large trades with signal scoring and persisted suspicion facts. Filter by size, category, trader grade, or persisted suspicion. Filters are applied before pagination, and every request uses SQL-backed limit + 1 pagination so has_more and next_cursor reflect the filtered result set. Cursor-paginated, newest first. Market categories come from provider-backed market_canonical identity. Returns trades on sports and esports markets only (#27430): a trade on any other market is not listed, not counted toward has_more, and not returned by since. Deprecated alias of GET /api/v1/large-trades, kept live until its sunset on 2027-02-01 (#16304, #29351); every response carries `Deprecation: @1790132400` (RFC 9745, 2026-09-23T03:00:00Z) and a `Link` to the successor (`rel=\"successor-version\"`) and to the versioning policy (`rel=\"deprecation\"`). `Sunset: Mon, 01 Feb 2027 00:00:00 GMT` (RFC 8594) names that date, after which the path answers 410 Gone with error.code endpoint_retired. The response adds a top-level `data_quality` object beside `data`, grouping alert, trade, trader, ranking, market, and volume fields by their database writer. `whale_alerts.inserted_xid` is reported as unknown because it is a transaction identifier rather than a timestamp. Its stored clocks are part of the ETag; `meta` continues to hold transport cache facts. Pass since to poll for new trades: the answer holds only the trades recorded after the one you name, and with If-None-Match a poll that finds none is 304 with an empty body.",
        "tags": ["Large trades"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of recent large trades to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Pagination cursor from previous response's next_cursor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_size",
            "in": "query",
            "description": "Minimum trade size in USD.",
            "schema": {
              "type": "number",
              "default": 5000
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "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).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_grade",
            "in": "query",
            "description": "Minimum trader grade now (trader.grade), the wallet's grade when this page is read, not when the trade filled. A wallet re-graded after a trade enters or leaves the result, so a catch-up read can disagree with GET /api/v1/stream and webhooks. For the grade at the fill, send min_grade_at_trade instead. A means S or A, B means S, A or B.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"]
            }
          },
          {
            "name": "min_grade_at_trade",
            "in": "query",
            "description": "Minimum grade the trader held when the trade filled (trader.grade_at_trade). Only rows whose trader.grade_at_trade_status is graded can match, so a trade before 2026-09-19T23:00Z, or one made while the wallet's grade was changing, never does. The same basis as min_grade_at_trade on GET /api/v1/stream and on webhook trade_filters, so a client that catches up here and then streams gets one answer. Applies to every path: recent, since, sort=market_volume_share, condition_id and event_slug. Sending it with min_grade is 400. A means S or A, B means S, A or B.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"]
            }
          },
          {
            "name": "suspicious_only",
            "in": "query",
            "description": "When true, return only rows with persisted suspicion_score >= 60. The filter is applied before SQL-backed limit + 1 pagination.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "min_market_volume_share",
            "in": "query",
            "description": "Keep only trades whose market_volume_share is known and at least this. A fraction, not a percent: 0.01 is one percent of the market's traded volume. A trade whose share is unavailable is never returned by a non-zero value, because an unavailable share cannot be said to clear a floor.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Order of the returned page. recent is newest first and is the default. market_volume_share ranks by each trade's share of its market's traded volume, biggest first, with a trade whose share is unavailable last. That ranking reads the last 30 days, because the share is computed for each request and an unbounded ranking cannot be served inside the documented latency budget. A cursor is bound to the order it was minted in, so a continuation cannot cross from one order into the other.",
            "schema": {
              "type": "string",
              "enum": ["recent", "market_volume_share"],
              "default": "recent"
            }
          },
          {
            "name": "since",
            "in": "query",
            "description": "Return only the trades recorded after this one. Pass the id of a large trade this API returned (wt_<n>, or the bare integer). The answer keeps the list shape and newest-first order, and next_cursor pages within it. After means commit order: a trade recorded late with an earlier traded_at is still returned, and a trade whose write has not committed yet is returned on a later poll, never skipped. To poll, send the id of the first trade on the first page of your last answer that had trades, with If-None-Match set to the ETag you last received; when nothing new was recorded the answer is 304 with an empty body. A late trade can come back once, so deduplicate on id. Only with sort=recent. An id that names no trade, or one more than 10000 trades behind the newest, answers 400 with error.param since; request the list without since and continue from its first trade.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "condition_id",
            "in": "query",
            "description": "Only this market's large trades: an exact raw provider condition_id. The page is read from the market's own index, newest first, and pages with cursor; it cannot be combined with since or with event_slug (400). An unknown market returns an empty list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "event_slug",
            "in": "query",
            "description": "Only the large trades in one game: every market of the game behind this event slug, the moneyline, spreads, totals and props, as GET /api/v1/games/{event_slug}/trades reads them. Matched case-insensitively. Newest first only (sort=market_volume_share answers 400), pages with cursor, and cannot be combined with since or with condition_id (400). An unknown slug answers 404 not_found with error.param event_slug.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of whale trades",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "data_quality", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LargeTrade"
                      }
                    },
                    "data_quality": {
                      "$ref": "#/components/schemas/DataQuality",
                      "description": "Writer-backed age and coverage for this page; it is part of the representation and the ETag, while transport cache facts remain in meta."
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total matching rows when the read model exposes a count; the key is absent when it does not."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [],
                      "data_quality": {
                        "status": "partial",
                        "field_groups": [
                          {
                            "group": "alert",
                            "owner": "whale_alerts.inserted_xid",
                            "status": "unknown",
                            "reason": "whale_alerts.inserted_xid is a transaction identifier rather than a timestamp"
                          },
                          {
                            "group": "trade",
                            "owner": "trades.ingested_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "trader",
                            "owner": "traders.last_synced",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "ranking",
                            "owner": "trader_rankings.computed_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "market",
                            "owner": "market_canonical.last_refreshed_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "volume",
                            "owner": "market_live_stats.volume_request_observed_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          }
                        ]
                      },
                      "has_more": false,
                      "total": 0,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Deprecation": {
                "description": "RFC 9745 structured-field date when this alias was deprecated (2026-09-23T03:00:00Z, #16304).",
                "schema": {
                  "type": "string",
                  "example": "@1790132400"
                }
              },
              "Link": {
                "description": "RFC 8288 links to the successor operation (rel=\"successor-version\") and the deprecation policy (rel=\"deprecation\").",
                "schema": {
                  "type": "string"
                }
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/whale-trades'"
          },
          {
            "lang": "curl",
            "label": "cURL (poll for new trades)",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  -H \"If-None-Match: $LAST_ETAG\" \\\n  \"https://api.0xinsider.com/api/v1/whale-trades?since=$NEWEST_TRADE_ID\""
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "deprecated": true
      }
    },
    "/api/v1/large-trades/history": {
      "get": {
        "operationId": "listLargeTradeHistory",
        "summary": "Replay historical large trades",
        "description": "Returns historical large trades from local whale_alerts rows, not request-time provider fetches. Filter by condition_id, trader, category, minimum grade, persisted suspicion, platform, and RFC3339 from/to windows. All filters are pushed into SQL before LIMIT, every request uses SQL-backed limit + 1 pagination, and results are ordered newest first by traded_at desc, id desc. Metadata exposes local_replay source and best_effort completeness. Returns trades on sports and esports markets only (#27430), across the whole archive: a stored trade on any other market is left out before LIMIT. POINT IN TIME: signal_score, trader.grade and the min_grade filter carry today's values on every row however old, so a backtest that selects by them selects wallets on what they did after the trade. The point-in-time fields are recorded_signal_score (from 2026-08-03T11:59Z; null before, and never backfilled, because the trader statistics it reads at insert were not kept for older rows) and trader.grade_at_trade with trader.grade_at_trade_status (from 2026-09-19T23:00Z; unknown before). CAPTURE RULES changed over the archive's life: rows before 2026-02-02 are sparse (at most a few hundred a month); from 2026-02-02 the floor was 3,000 USD (1.4% of rows through 2026-07-05 are smaller) and trades at any price were kept; from 2026-07-06 a trade is kept at 10,000 USD or more (1,000 USD in earnings markets) and only when priced below 0.97 (0.99 in earnings markets). Pass min_size=10000 for one size rule across the whole range; monthly row counts still follow the sports calendar. Until 2026-07-17 one match could be stored twice, once per wallet: from 2026-05-01 to 2026-07-17, 27.7% of rows at 10,000 USD or more share a transaction and market with another stored wallet, almost always a Yes buyer and a No buyer filled against each other. From 2026-07-18 a row is the taker's side only. Before 2026-05 the transaction hash is mostly absent, so the share cannot be measured there. From 2026-09-23 a fill must ALSO be at least 0.1% of its market's recorded traded volume, Polymarket's own share count, so a $10,000 print that lands in a market which has already traded tens of millions of shares is no longer kept; a market with no positive recorded volume keeps the fill; rows written before that date were not re-filtered. The response adds a top-level `data_quality` object beside `data`, grouping alert, trade, trader, ranking, market, and volume fields by their database writer. `whale_alerts.inserted_xid` is reported as unknown because it is a transaction identifier rather than a timestamp. Its stored clocks are part of the ETag; `meta` continues to hold transport cache facts.",
        "tags": ["Large trades"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of historical large trades to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Pagination cursor from previous response's next_cursor. Prefix: wth_. URL-encode when replaying as a query parameter.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_size",
            "in": "query",
            "description": "Minimum trade size in USD. The capture floor was 3,000 USD before 2026-07-06 and 10,000 USD from then (1,000 USD in earnings markets), so 10000 gives one size rule across the whole archive. From 2026-09-23 a fill must also be at least 0.1% of its market's recorded traded volume (Polymarket's own share count), where a positive volume is recorded for the market; a market without one keeps the fill, and rows written before that date were not re-filtered.",
            "schema": {
              "type": "number",
              "default": 5000
            }
          },
          {
            "name": "condition_id",
            "in": "query",
            "description": "Exact raw provider condition_id. Unknown markets return an empty list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "trader",
            "in": "query",
            "description": "Trader wallet address, timestamp-suffixed wallet alias, username, or trd_-prefixed trader ID, resolved against the traders table. Unknown traders return an empty list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "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).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_grade",
            "in": "query",
            "description": "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 send min_grade_at_trade instead, which filters on trader.grade_at_trade. A means S or A, B means S, A or B.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"]
            }
          },
          {
            "name": "min_grade_at_trade",
            "in": "query",
            "description": "Minimum grade the trader held when the trade filled (trader.grade_at_trade). Only rows whose trader.grade_at_trade_status is graded can match, so a trade before 2026-09-19T23:00Z, or one made while the wallet's grade was changing, never does. The same basis as min_grade_at_trade on GET /api/v1/large-trades, GET /api/v1/stream and webhook trade_filters, so a history read and a stream with the same floor agree. Applies to both sorts and beside condition_id, event_slug, trader and from/to. Sending it with min_grade is 400. A means S or A, B means S, A or B.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"]
            }
          },
          {
            "name": "suspicious_only",
            "in": "query",
            "description": "When true, return only rows with persisted suspicion_score >= 60. The filter is applied before SQL-backed limit + 1 pagination.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "platform",
            "in": "query",
            "description": "Filter by whale_alerts.platform. all is equivalent to omitted.",
            "schema": {
              "type": "string",
              "enum": ["polymarket", "all"]
            }
          },
          {
            "name": "from",
            "in": "query",
            "description": "Inclusive RFC3339 lower bound on whale_alerts.traded_at.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Exclusive RFC3339 upper bound on whale_alerts.traded_at. Must be after from when both are present.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "min_market_volume_share",
            "in": "query",
            "description": "Keep only trades whose market_volume_share is known and at least this. A fraction, not a percent: 0.01 is one percent of the market's traded volume. A trade whose share is unavailable is never returned by a non-zero value, because an unavailable share cannot be said to clear a floor.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Order of the returned page. recent is newest first and is the default. market_volume_share ranks by each trade's share of its market's traded volume, biggest first, with a trade whose share is unavailable last. That ranking reads from, or the last 30 days when from is omitted, for the same reason. A cursor is bound to the order it was minted in, so a continuation cannot cross from one order into the other.",
            "schema": {
              "type": "string",
              "enum": ["recent", "market_volume_share"],
              "default": "recent"
            }
          },
          {
            "name": "event_slug",
            "in": "query",
            "description": "Only the large trades in one game: every market of the game behind this event slug, the moneyline, spreads, totals and props, as GET /api/v1/games/{event_slug}/trades reads them. Matched case-insensitively. Newest first only (sort=market_volume_share answers 400), and cannot be combined with condition_id (400). An unknown slug answers 404 not_found with error.param event_slug.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Historical large trade replay",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "data_quality", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LargeTrade"
                      }
                    },
                    "data_quality": {
                      "$ref": "#/components/schemas/DataQuality",
                      "description": "Writer-backed age and coverage for this page; it is part of the representation and the ETag, while transport cache facts remain in meta."
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total matching rows when the read model exposes a count; the key is absent when it does not."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/LargeTradeHistoryMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [
                        {
                          "id": "wt_392079",
                          "traded_at": "2026-09-22T02:05:52Z",
                          "size_usd": 19232.92,
                          "side": "BUY",
                          "outcome": "Rams",
                          "clv": {
                            "status": "in_play",
                            "unavailable_reason": null,
                            "pre_kickoff": false,
                            "close_anchor_at": "2026-09-22T00:20:00Z",
                            "close_price": 0.615,
                            "clv_cents": null,
                            "taker_fee_cents": 0.2829,
                            "clv_after_fees_cents": null,
                            "basis_version": "clv@v1"
                          },
                          "token_id": "43677542496120548237382622015301078356830156697348317225498679221043021866409",
                          "price": 0.9398,
                          "review_score": 0.3959,
                          "signal_score": 0.3959,
                          "recorded_review_score": 0.4041,
                          "recorded_signal_score": 0.4041,
                          "market_volume_share": 0.002852,
                          "suspicion_score": null,
                          "suspicion_track": null,
                          "trader": {
                            "id": "trd_0xabc1230000000000000000000000000000000abc",
                            "address": "0xabc1230000000000000000000000000000000abc",
                            "username": "example_trader",
                            "grade": "F",
                            "grade_at_trade": "F",
                            "grade_at_trade_status": "graded"
                          },
                          "market": {
                            "id": "mkt_0xdef4560000000000000000000000000000000def613f54180a6d82f81c586f87",
                            "condition_id": "0xdef4560000000000000000000000000000000def613f54180a6d82f81c586f87",
                            "title": "Giants vs. Rams",
                            "slug": "nfl-nyg-la-2026-09-22",
                            "category": "NFL"
                          }
                        },
                        {
                          "id": "wt_392077",
                          "traded_at": "2026-09-22T02:04:20Z",
                          "size_usd": 16292.73,
                          "side": "BUY",
                          "outcome": "Dallas Wings",
                          "clv": {
                            "status": "measured",
                            "unavailable_reason": null,
                            "pre_kickoff": true,
                            "close_anchor_at": "2026-09-22T02:30:00Z",
                            "close_price": 0.665,
                            "clv_cents": 1.5,
                            "taker_fee_cents": 1.1375,
                            "clv_after_fees_cents": 0.3625,
                            "basis_version": "clv@v1"
                          },
                          "token_id": "26603239767113701790776634803790654539492519362779665632490658212718064984767",
                          "price": 0.65,
                          "review_score": 0.33,
                          "signal_score": 0.33,
                          "recorded_review_score": 0.3383,
                          "recorded_signal_score": 0.3383,
                          "market_volume_share": 0.528557,
                          "suspicion_score": null,
                          "suspicion_track": null,
                          "trader": {
                            "id": "trd_0xdef4560000000000000000000000000000000def",
                            "address": "0xdef4560000000000000000000000000000000def",
                            "grade_at_trade": null,
                            "grade_at_trade_status": "unknown"
                          },
                          "market": {
                            "id": "mkt_0xdef4560000000000000000000000000000000def4c2638b15eda50ca1b7ce303",
                            "condition_id": "0xdef4560000000000000000000000000000000def4c2638b15eda50ca1b7ce303",
                            "title": "Dallas Wings vs. Phoenix Mercury",
                            "slug": "wnba-dal-phx-2026-09-21",
                            "category": "WNBA"
                          }
                        }
                      ],
                      "data_quality": {
                        "status": "partial",
                        "field_groups": [
                          {
                            "group": "alert",
                            "owner": "whale_alerts.inserted_xid",
                            "status": "unknown",
                            "reason": "whale_alerts.inserted_xid is a transaction identifier rather than a timestamp"
                          },
                          {
                            "group": "trade",
                            "owner": "trades.ingested_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "trader",
                            "owner": "traders.last_synced",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "ranking",
                            "owner": "trader_rankings.computed_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "market",
                            "owner": "market_canonical.last_refreshed_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "volume",
                            "owner": "market_live_stats.volume_request_observed_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          }
                        ]
                      },
                      "has_more": true,
                      "next_cursor": "2026-09-22T02:04:20+00:00_wth_392077",
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "source": {
                          "kind": "local_replay",
                          "table": "whale_alerts",
                          "provider_fetch_at_request_time": false
                        },
                        "completeness": {
                          "status": "best_effort",
                          "reason": "Historical whale trades are replayed from local whale_alerts rows; provider backfill completeness can vary by market and time window."
                        }
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/large-trades/history'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "data_quality": {
              "status": "partial",
              "field_groups": [
                {
                  "group": "alert",
                  "owner": "whale_alerts.inserted_xid",
                  "status": "unknown",
                  "reason": "whale_alerts.inserted_xid is a transaction identifier rather than a timestamp"
                },
                {
                  "group": "trade",
                  "owner": "trades.ingested_at",
                  "status": "unknown",
                  "reason": "the page returned no large-trade row from which to read this writer clock"
                },
                {
                  "group": "trader",
                  "owner": "traders.last_synced",
                  "status": "unknown",
                  "reason": "the page returned no large-trade row from which to read this writer clock"
                },
                {
                  "group": "ranking",
                  "owner": "trader_rankings.computed_at",
                  "status": "unknown",
                  "reason": "the page returned no large-trade row from which to read this writer clock"
                },
                {
                  "group": "market",
                  "owner": "market_canonical.last_refreshed_at",
                  "status": "unknown",
                  "reason": "the page returned no large-trade row from which to read this writer clock"
                },
                {
                  "group": "volume",
                  "owner": "market_live_stats.volume_request_observed_at",
                  "status": "unknown",
                  "reason": "the page returned no large-trade row from which to read this writer clock"
                }
              ]
            },
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/whale-trades/history": {
      "get": {
        "operationId": "listWhaleTradeHistory",
        "summary": "Replay historical whale trades",
        "description": "Returns historical whale trades from local whale_alerts rows, not request-time provider fetches. Filter by condition_id, trader, category, minimum grade, persisted suspicion, platform, and RFC3339 from/to windows. All filters are pushed into SQL before LIMIT, every request uses SQL-backed limit + 1 pagination, and results are ordered newest first by traded_at desc, id desc. Metadata exposes local_replay source and best_effort completeness. Returns trades on sports and esports markets only (#27430), across the whole archive: a stored trade on any other market is left out before LIMIT. Deprecated alias of GET /api/v1/large-trades/history, kept live until its sunset on 2027-02-01 (#16304, #29351); every response carries `Deprecation: @1790132400` (RFC 9745, 2026-09-23T03:00:00Z) and a `Link` to the successor (`rel=\"successor-version\"`) and to the versioning policy (`rel=\"deprecation\"`). `Sunset: Mon, 01 Feb 2027 00:00:00 GMT` (RFC 8594) names that date, after which the path answers 410 Gone with error.code endpoint_retired. The response adds a top-level `data_quality` object beside `data`, grouping alert, trade, trader, ranking, market, and volume fields by their database writer. `whale_alerts.inserted_xid` is reported as unknown because it is a transaction identifier rather than a timestamp. Its stored clocks are part of the ETag; `meta` continues to hold transport cache facts.",
        "tags": ["Large trades"],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of historical large trades to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Pagination cursor from previous response's next_cursor. Prefix: wth_. URL-encode when replaying as a query parameter.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_size",
            "in": "query",
            "description": "Minimum trade size in USD.",
            "schema": {
              "type": "number",
              "default": 5000
            }
          },
          {
            "name": "condition_id",
            "in": "query",
            "description": "Exact raw provider condition_id. Unknown markets return an empty list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "trader",
            "in": "query",
            "description": "Trader wallet address, timestamp-suffixed wallet alias, or username resolved against the traders table. Unknown traders return an empty list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "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).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_grade",
            "in": "query",
            "description": "Minimum trader grade.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"]
            }
          },
          {
            "name": "min_grade_at_trade",
            "in": "query",
            "description": "Minimum grade the trader held when the trade filled (trader.grade_at_trade). Only rows whose trader.grade_at_trade_status is graded can match, so a trade before 2026-09-19T23:00Z, or one made while the wallet's grade was changing, never does. The same basis as min_grade_at_trade on GET /api/v1/large-trades, GET /api/v1/stream and webhook trade_filters, so a history read and a stream with the same floor agree. Applies to both sorts and beside condition_id, event_slug, trader and from/to. Sending it with min_grade is 400. A means S or A, B means S, A or B.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"]
            }
          },
          {
            "name": "suspicious_only",
            "in": "query",
            "description": "When true, return only rows with persisted suspicion_score >= 60. The filter is applied before SQL-backed limit + 1 pagination.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "platform",
            "in": "query",
            "description": "Filter by whale_alerts.platform. all is equivalent to omitted.",
            "schema": {
              "type": "string",
              "enum": ["polymarket", "all"]
            }
          },
          {
            "name": "from",
            "in": "query",
            "description": "Inclusive RFC3339 lower bound on whale_alerts.traded_at.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Exclusive RFC3339 upper bound on whale_alerts.traded_at. Must be after from when both are present.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "min_market_volume_share",
            "in": "query",
            "description": "Keep only trades whose market_volume_share is known and at least this. A fraction, not a percent: 0.01 is one percent of the market's traded volume. A trade whose share is unavailable is never returned by a non-zero value, because an unavailable share cannot be said to clear a floor.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Order of the returned page. recent is newest first and is the default. market_volume_share ranks by each trade's share of its market's traded volume, biggest first, with a trade whose share is unavailable last. That ranking reads from, or the last 30 days when from is omitted, for the same reason. A cursor is bound to the order it was minted in, so a continuation cannot cross from one order into the other.",
            "schema": {
              "type": "string",
              "enum": ["recent", "market_volume_share"],
              "default": "recent"
            }
          },
          {
            "name": "event_slug",
            "in": "query",
            "description": "Only the large trades in one game: every market of the game behind this event slug, the moneyline, spreads, totals and props, as GET /api/v1/games/{event_slug}/trades reads them. Matched case-insensitively. Newest first only (sort=market_volume_share answers 400), and cannot be combined with condition_id (400). An unknown slug answers 404 not_found with error.param event_slug.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Historical whale trade replay",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "data_quality", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LargeTrade"
                      }
                    },
                    "data_quality": {
                      "$ref": "#/components/schemas/DataQuality",
                      "description": "Writer-backed age and coverage for this page; it is part of the representation and the ETag, while transport cache facts remain in meta."
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total matching rows when the read model exposes a count; absent (or null) when it does not."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/LargeTradeHistoryMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [
                        {
                          "id": "wt_392079",
                          "traded_at": "2026-09-22T02:05:52Z",
                          "size_usd": 19232.92,
                          "side": "BUY",
                          "outcome": "Rams",
                          "clv": {
                            "status": "in_play",
                            "unavailable_reason": null,
                            "pre_kickoff": false,
                            "close_anchor_at": "2026-09-22T00:20:00Z",
                            "close_price": 0.615,
                            "clv_cents": null,
                            "taker_fee_cents": 0.2829,
                            "clv_after_fees_cents": null,
                            "basis_version": "clv@v1"
                          },
                          "token_id": "43677542496120548237382622015301078356830156697348317225498679221043021866409",
                          "price": 0.9398,
                          "review_score": 0.3959,
                          "signal_score": 0.3959,
                          "recorded_review_score": 0.4041,
                          "recorded_signal_score": 0.4041,
                          "market_volume_share": 0.002852,
                          "suspicion_score": null,
                          "suspicion_track": null,
                          "trader": {
                            "id": "trd_0xabc1230000000000000000000000000000000abc",
                            "address": "0xabc1230000000000000000000000000000000abc",
                            "username": "example_trader",
                            "grade": "F",
                            "grade_at_trade": "F",
                            "grade_at_trade_status": "graded"
                          },
                          "market": {
                            "id": "mkt_0xdef4560000000000000000000000000000000def613f54180a6d82f81c586f87",
                            "condition_id": "0xdef4560000000000000000000000000000000def613f54180a6d82f81c586f87",
                            "title": "Giants vs. Rams",
                            "slug": "nfl-nyg-la-2026-09-22",
                            "category": "NFL"
                          }
                        },
                        {
                          "id": "wt_392077",
                          "traded_at": "2026-09-22T02:04:20Z",
                          "size_usd": 16292.73,
                          "side": "BUY",
                          "outcome": "Dallas Wings",
                          "clv": {
                            "status": "measured",
                            "unavailable_reason": null,
                            "pre_kickoff": true,
                            "close_anchor_at": "2026-09-22T02:30:00Z",
                            "close_price": 0.665,
                            "clv_cents": 1.5,
                            "taker_fee_cents": 1.1375,
                            "clv_after_fees_cents": 0.3625,
                            "basis_version": "clv@v1"
                          },
                          "token_id": "26603239767113701790776634803790654539492519362779665632490658212718064984767",
                          "price": 0.65,
                          "review_score": 0.33,
                          "signal_score": 0.33,
                          "recorded_review_score": 0.3383,
                          "recorded_signal_score": 0.3383,
                          "market_volume_share": 0.528557,
                          "suspicion_score": null,
                          "suspicion_track": null,
                          "trader": {
                            "id": "trd_0xdef4560000000000000000000000000000000def",
                            "address": "0xdef4560000000000000000000000000000000def",
                            "grade_at_trade": null,
                            "grade_at_trade_status": "unknown"
                          },
                          "market": {
                            "id": "mkt_0xdef4560000000000000000000000000000000def4c2638b15eda50ca1b7ce303",
                            "condition_id": "0xdef4560000000000000000000000000000000def4c2638b15eda50ca1b7ce303",
                            "title": "Dallas Wings vs. Phoenix Mercury",
                            "slug": "wnba-dal-phx-2026-09-21",
                            "category": "WNBA"
                          }
                        }
                      ],
                      "data_quality": {
                        "status": "partial",
                        "field_groups": [
                          {
                            "group": "alert",
                            "owner": "whale_alerts.inserted_xid",
                            "status": "unknown",
                            "reason": "whale_alerts.inserted_xid is a transaction identifier rather than a timestamp"
                          },
                          {
                            "group": "trade",
                            "owner": "trades.ingested_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "trader",
                            "owner": "traders.last_synced",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "ranking",
                            "owner": "trader_rankings.computed_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "market",
                            "owner": "market_canonical.last_refreshed_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          },
                          {
                            "group": "volume",
                            "owner": "market_live_stats.volume_request_observed_at",
                            "status": "unknown",
                            "reason": "the page returned no large-trade row from which to read this writer clock"
                          }
                        ]
                      },
                      "has_more": true,
                      "next_cursor": "2026-09-22T02:04:20+00:00_wth_392077",
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "source": {
                          "kind": "local_replay",
                          "table": "whale_alerts",
                          "provider_fetch_at_request_time": false
                        },
                        "completeness": {
                          "status": "best_effort",
                          "reason": "Historical whale trades are replayed from local whale_alerts rows; provider backfill completeness can vary by market and time window."
                        }
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Deprecation": {
                "description": "RFC 9745 structured-field date when this alias was deprecated (2026-09-23T03:00:00Z, #16304).",
                "schema": {
                  "type": "string",
                  "example": "@1790132400"
                }
              },
              "Link": {
                "description": "RFC 8288 links to the successor operation (rel=\"successor-version\") and the deprecation policy (rel=\"deprecation\").",
                "schema": {
                  "type": "string"
                }
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/whale-trades/history'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "deprecated": true
      }
    },
    "/api/v1/large-trades/{id}": {
      "get": {
        "operationId": "getLargeTrade",
        "summary": "Get large trade by ID",
        "description": "Returns one large trade by raw whale_alerts.id or the wt_-prefixed id emitted by list and history responses.",
        "tags": ["Large trades"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Raw whale_alerts.id or wt_-prefixed large trade id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Large trade",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "large_trade"
                    },
                    "data": {
                      "$ref": "#/components/schemas/LargeTradeDetail"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "large_trade",
                      "data": {
                        "id": "wt_392079",
                        "traded_at": "2026-09-22T02:05:52Z",
                        "size_usd": 19232.92,
                        "side": "BUY",
                        "outcome": "Rams",
                        "clv": {
                          "status": "in_play",
                          "unavailable_reason": null,
                          "pre_kickoff": false,
                          "close_anchor_at": "2026-09-22T00:20:00Z",
                          "close_price": 0.615,
                          "clv_cents": null,
                          "taker_fee_cents": 0.2829,
                          "clv_after_fees_cents": null,
                          "basis_version": "clv@v1"
                        },
                        "token_id": "43677542496120548237382622015301078356830156697348317225498679221043021866409",
                        "price": 0.9398,
                        "review_score": 0.3959,
                        "signal_score": 0.3959,
                        "recorded_review_score": 0.4041,
                        "recorded_signal_score": 0.4041,
                        "market_volume_share": 0.002852,
                        "suspicion_score": null,
                        "suspicion_track": null,
                        "trader": {
                          "id": "trd_0xabc1230000000000000000000000000000000abc",
                          "address": "0xabc1230000000000000000000000000000000abc",
                          "username": "example_trader",
                          "grade": "F",
                          "grade_at_trade": "F",
                          "grade_at_trade_status": "graded"
                        },
                        "market": {
                          "id": "mkt_0xdef4560000000000000000000000000000000def613f54180a6d82f81c586f87",
                          "condition_id": "0xdef4560000000000000000000000000000000def613f54180a6d82f81c586f87",
                          "title": "Giants vs. Rams",
                          "slug": "nfl-nyg-la-2026-09-22",
                          "category": "NFL"
                        },
                        "counterparty_analysis": {
                          "status": "unavailable",
                          "unavailable_reason": "worker_disabled",
                          "execution_count": 1,
                          "available_execution_count": 0,
                          "unavailable_execution_count": 1,
                          "executions": []
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27304): the large trade is real but its market is outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this trade. Without error.reason, no large trade with this id is visible to the V1 projection: none is stored, or a stored trade's trader or market enrichment has not synced yet, so a trade a list just returned can become visible on a later request (#27581). Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/large-trades/wt_123'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "large_trade",
            "data": {},
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/whale-trades/{id}": {
      "get": {
        "operationId": "getWhaleTrade",
        "summary": "Get whale trade by ID",
        "description": "Returns one whale trade by raw whale_alerts.id or the wt_-prefixed id emitted by list and history responses. Deprecated alias of GET /api/v1/large-trades/{id}, kept live until its sunset on 2027-02-01 (#16304, #29351); every response carries `Deprecation: @1790132400` (RFC 9745, 2026-09-23T03:00:00Z) and a `Link` to the successor (`rel=\"successor-version\"`) and to the versioning policy (`rel=\"deprecation\"`). `Sunset: Mon, 01 Feb 2027 00:00:00 GMT` (RFC 8594) names that date, after which the path answers 410 Gone with error.code endpoint_retired.",
        "tags": ["Large trades"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Raw whale_alerts.id or wt_-prefixed whale trade id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Whale trade",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "whale_trade"
                    },
                    "data": {
                      "$ref": "#/components/schemas/LargeTradeDetail"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "whale_trade",
                      "data": {
                        "id": "wt_392079",
                        "traded_at": "2026-09-22T02:05:52Z",
                        "size_usd": 19232.92,
                        "side": "BUY",
                        "outcome": "Rams",
                        "clv": {
                          "status": "in_play",
                          "unavailable_reason": null,
                          "pre_kickoff": false,
                          "close_anchor_at": "2026-09-22T00:20:00Z",
                          "close_price": 0.615,
                          "clv_cents": null,
                          "taker_fee_cents": 0.2829,
                          "clv_after_fees_cents": null,
                          "basis_version": "clv@v1"
                        },
                        "token_id": "43677542496120548237382622015301078356830156697348317225498679221043021866409",
                        "price": 0.9398,
                        "review_score": 0.3959,
                        "signal_score": 0.3959,
                        "recorded_review_score": 0.4041,
                        "recorded_signal_score": 0.4041,
                        "market_volume_share": 0.002852,
                        "suspicion_score": null,
                        "suspicion_track": null,
                        "trader": {
                          "id": "trd_0xabc1230000000000000000000000000000000abc",
                          "address": "0xabc1230000000000000000000000000000000abc",
                          "username": "example_trader",
                          "grade": "F",
                          "grade_at_trade": "F",
                          "grade_at_trade_status": "graded"
                        },
                        "market": {
                          "id": "mkt_0xdef4560000000000000000000000000000000def613f54180a6d82f81c586f87",
                          "condition_id": "0xdef4560000000000000000000000000000000def613f54180a6d82f81c586f87",
                          "title": "Giants vs. Rams",
                          "slug": "nfl-nyg-la-2026-09-22",
                          "category": "NFL"
                        },
                        "counterparty_analysis": {
                          "status": "unavailable",
                          "unavailable_reason": "worker_disabled",
                          "execution_count": 1,
                          "available_execution_count": 0,
                          "unavailable_execution_count": 1,
                          "executions": []
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Deprecation": {
                "description": "RFC 9745 structured-field date when this alias was deprecated (2026-09-23T03:00:00Z, #16304).",
                "schema": {
                  "type": "string",
                  "example": "@1790132400"
                }
              },
              "Link": {
                "description": "RFC 8288 links to the successor operation (rel=\"successor-version\") and the deprecation policy (rel=\"deprecation\").",
                "schema": {
                  "type": "string"
                }
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27304): the large trade is real but its market is outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this trade. Without error.reason, no large trade with this id is visible to the V1 projection: none is stored, or a stored trade's trader or market enrichment has not synced yet, so a trade a list just returned can become visible on a later request (#27581). Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/whale-trades/wt_123'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "whale_trade",
            "data": {},
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "deprecated": true
      }
    },
    "/api/v1/large-trades/{id}/counterparties/executions": {
      "get": {
        "operationId": "listLargeTradeCounterpartyExecutions",
        "summary": "Page counterparty executions",
        "description": "Returns a bounded execution page from the immutable snapshot emitted by large-trade detail. A stale or changed snapshot returns a cursor-expired error so clients restart from detail.",
        "tags": ["Large trades"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Large trade ID. Accepts wt_-prefixed or raw whale_alerts.id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "snapshot_id",
            "in": "query",
            "required": true,
            "description": "Counterparty snapshot ID from the large trade detail response.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque cursor from the previous response's next_cursor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of counterparty execution rows to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Counterparty execution page",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "counterparty_analysis"
                    },
                    "data": {
                      "$ref": "#/components/schemas/CounterpartyAnalysis"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Bad request. On this cursor-paginated route a 400 has TWO distinct causes; branch on error.reason. (1) error.reason=\"cursor_expired\" (with error.param=\"cursor\"): the pagination cursor was invalidated by an upstream data change mid-walk (e.g. the ranking snapshot behind the page refreshed). It is NOT a malformed parameter and NOT a reason to stop: recovery is mechanical -- re-request the first page and walk forward again. There is deliberately no Retry-After and no error.retry_at, because waiting changes nothing. (2) no error.reason: an ordinary invalid request parameter -- check error.param when present, otherwise error.message. Both carry error.code=\"bad_request\" (a FROZEN contract value), so error.reason is the discriminator.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27304): the large trade is real but its market is outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this trade. Without error.reason, either no large trade with this id is visible to the V1 projection (none is stored, or a stored trade's enrichment has not synced yet), or snapshot_id names no stored counterparty snapshot, or a snapshot of another trade: read the trade's detail for its current snapshot_id and restart from there (#27581). Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. On this route a 503 has TWO distinct causes; branch on error.reason. (1) error.reason=\"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; consult that endpoint's contract and do not infer dependency health from this shared reason. This is endpoint-local unavailability, not rate limiting: retry only this route after Retry-After (or error.retry_at), and do not feed it into a rate-limit backoff shared with other endpoints. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the seconds until it probes Redis again. Both carry error.code=\"rate_limit_unavailable\" (a FROZEN contract value, so it cannot be split per cause) and X-Request-Id -- which is why error.reason, not error.code, is the discriminator.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until retrying is worth doing. With error.reason=\"read_model_warming\" this is the endpoint-local read-model retry interval; without a reason it is the rate-limiter outage cooldown. Always >= 1.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/whale-trades/{id}/counterparties/executions": {
      "get": {
        "operationId": "listWhaleTradeCounterpartyExecutions",
        "summary": "Page counterparty executions",
        "description": "Returns a bounded execution page from the immutable snapshot emitted by whale-trade detail. A stale or changed snapshot returns a cursor-expired error so clients restart from detail. Deprecated alias of GET /api/v1/large-trades/{id}/counterparties/executions, kept live until its sunset on 2027-02-01 (#16304, #29351); every response carries `Deprecation: @1790132400` (RFC 9745, 2026-09-23T03:00:00Z) and a `Link` to the successor (`rel=\"successor-version\"`) and to the versioning policy (`rel=\"deprecation\"`). `Sunset: Mon, 01 Feb 2027 00:00:00 GMT` (RFC 8594) names that date, after which the path answers 410 Gone with error.code endpoint_retired.",
        "tags": ["Large trades"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Whale trade ID. Accepts wt_-prefixed or raw whale_alerts.id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "snapshot_id",
            "in": "query",
            "required": true,
            "description": "Counterparty snapshot ID from the whale trade detail response.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque cursor from the previous response's next_cursor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of counterparty execution rows to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Counterparty execution page",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "counterparty_analysis"
                    },
                    "data": {
                      "$ref": "#/components/schemas/CounterpartyAnalysis"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                }
              }
            },
            "headers": {
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Deprecation": {
                "description": "RFC 9745 structured-field date when this alias was deprecated (2026-09-23T03:00:00Z, #16304).",
                "schema": {
                  "type": "string",
                  "example": "@1790132400"
                }
              },
              "Link": {
                "description": "RFC 8288 links to the successor operation (rel=\"successor-version\") and the deprecation policy (rel=\"deprecation\").",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Bad request. On this cursor-paginated route a 400 has TWO distinct causes; branch on error.reason. (1) error.reason=\"cursor_expired\" (with error.param=\"cursor\"): the pagination cursor was invalidated by an upstream data change mid-walk (e.g. the ranking snapshot behind the page refreshed). It is NOT a malformed parameter and NOT a reason to stop: recovery is mechanical -- re-request the first page and walk forward again. There is deliberately no Retry-After and no error.retry_at, because waiting changes nothing. (2) no error.reason: an ordinary invalid request parameter -- check error.param when present, otherwise error.message. Both carry error.code=\"bad_request\" (a FROZEN contract value), so error.reason is the discriminator.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27304): the large trade is real but its market is outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this trade. Without error.reason, either no large trade with this id is visible to the V1 projection (none is stored, or a stored trade's enrichment has not synced yet), or snapshot_id names no stored counterparty snapshot, or a snapshot of another trade: read the trade's detail for its current snapshot_id and restart from there (#27581). Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. On this route a 503 has TWO distinct causes; branch on error.reason. (1) error.reason=\"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; consult that endpoint's contract and do not infer dependency health from this shared reason. This is endpoint-local unavailability, not rate limiting: retry only this route after Retry-After (or error.retry_at), and do not feed it into a rate-limit backoff shared with other endpoints. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the seconds until it probes Redis again. Both carry error.code=\"rate_limit_unavailable\" (a FROZEN contract value, so it cannot be split per cause) and X-Request-Id -- which is why error.reason, not error.code, is the discriminator.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until retrying is worth doing. With error.reason=\"read_model_warming\" this is the endpoint-local read-model retry interval; without a reason it is the rate-limiter outage cooldown. Always >= 1.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "deprecated": true
      }
    },
    "/api/v1/large-trades/{id}/counterparties/executions/{execution_id}/makers": {
      "get": {
        "operationId": "listLargeTradeCounterpartyMakers",
        "summary": "Page maker counterparties",
        "description": "Returns a bounded maker-wallet page for one exact execution. Percentages keep the complete execution denominator across pages.",
        "tags": ["Large trades"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Large trade ID. Accepts wt_-prefixed or raw whale_alerts.id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "execution_id",
            "in": "path",
            "required": true,
            "description": "Counterparty execution ID from the parent response.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "snapshot_id",
            "in": "query",
            "required": true,
            "description": "Counterparty snapshot ID from the large trade detail response.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque cursor from the previous response's next_cursor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of maker rows to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Counterparty maker page",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "counterparty_maker_page"
                    },
                    "data": {
                      "$ref": "#/components/schemas/CounterpartyMakerPage"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Bad request. On this cursor-paginated route a 400 has TWO distinct causes; branch on error.reason. (1) error.reason=\"cursor_expired\" (with error.param=\"cursor\"): the pagination cursor was invalidated by an upstream data change mid-walk (e.g. the ranking snapshot behind the page refreshed). It is NOT a malformed parameter and NOT a reason to stop: recovery is mechanical -- re-request the first page and walk forward again. There is deliberately no Retry-After and no error.retry_at, because waiting changes nothing. (2) no error.reason: an ordinary invalid request parameter -- check error.param when present, otherwise error.message. Both carry error.code=\"bad_request\" (a FROZEN contract value), so error.reason is the discriminator.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27304): the large trade is real but its market is outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this trade. Without error.reason, either no large trade with this id is visible to the V1 projection (none is stored, or a stored trade's enrichment has not synced yet), or snapshot_id names no stored counterparty snapshot, or a snapshot of another trade: read the trade's detail for its current snapshot_id and restart from there (#27581). Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. On this route a 503 has TWO distinct causes; branch on error.reason. (1) error.reason=\"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; consult that endpoint's contract and do not infer dependency health from this shared reason. This is endpoint-local unavailability, not rate limiting: retry only this route after Retry-After (or error.retry_at), and do not feed it into a rate-limit backoff shared with other endpoints. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the seconds until it probes Redis again. Both carry error.code=\"rate_limit_unavailable\" (a FROZEN contract value, so it cannot be split per cause) and X-Request-Id -- which is why error.reason, not error.code, is the discriminator.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until retrying is worth doing. With error.reason=\"read_model_warming\" this is the endpoint-local read-model retry interval; without a reason it is the rate-limiter outage cooldown. Always >= 1.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/whale-trades/{id}/counterparties/executions/{execution_id}/makers": {
      "get": {
        "operationId": "listWhaleTradeCounterpartyMakers",
        "summary": "Page maker counterparties",
        "description": "Returns a bounded maker-wallet page for one exact execution. Percentages keep the complete execution denominator across pages. Deprecated alias of GET /api/v1/large-trades/{id}/counterparties/executions/{execution_id}/makers, kept live until its sunset on 2027-02-01 (#16304, #29351); every response carries `Deprecation: @1790132400` (RFC 9745, 2026-09-23T03:00:00Z) and a `Link` to the successor (`rel=\"successor-version\"`) and to the versioning policy (`rel=\"deprecation\"`). `Sunset: Mon, 01 Feb 2027 00:00:00 GMT` (RFC 8594) names that date, after which the path answers 410 Gone with error.code endpoint_retired.",
        "tags": ["Large trades"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Whale trade ID. Accepts wt_-prefixed or raw whale_alerts.id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "execution_id",
            "in": "path",
            "required": true,
            "description": "Counterparty execution ID from the parent response.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "snapshot_id",
            "in": "query",
            "required": true,
            "description": "Counterparty snapshot ID from the whale trade detail response.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque cursor from the previous response's next_cursor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of maker rows to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Counterparty maker page",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "counterparty_maker_page"
                    },
                    "data": {
                      "$ref": "#/components/schemas/CounterpartyMakerPage"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                }
              }
            },
            "headers": {
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Deprecation": {
                "description": "RFC 9745 structured-field date when this alias was deprecated (2026-09-23T03:00:00Z, #16304).",
                "schema": {
                  "type": "string",
                  "example": "@1790132400"
                }
              },
              "Link": {
                "description": "RFC 8288 links to the successor operation (rel=\"successor-version\") and the deprecation policy (rel=\"deprecation\").",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Bad request. On this cursor-paginated route a 400 has TWO distinct causes; branch on error.reason. (1) error.reason=\"cursor_expired\" (with error.param=\"cursor\"): the pagination cursor was invalidated by an upstream data change mid-walk (e.g. the ranking snapshot behind the page refreshed). It is NOT a malformed parameter and NOT a reason to stop: recovery is mechanical -- re-request the first page and walk forward again. There is deliberately no Retry-After and no error.retry_at, because waiting changes nothing. (2) no error.reason: an ordinary invalid request parameter -- check error.param when present, otherwise error.message. Both carry error.code=\"bad_request\" (a FROZEN contract value), so error.reason is the discriminator.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27304): the large trade is real but its market is outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this trade. Without error.reason, either no large trade with this id is visible to the V1 projection (none is stored, or a stored trade's enrichment has not synced yet), or snapshot_id names no stored counterparty snapshot, or a snapshot of another trade: read the trade's detail for its current snapshot_id and restart from there (#27581). Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. On this route a 503 has TWO distinct causes; branch on error.reason. (1) error.reason=\"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; consult that endpoint's contract and do not infer dependency health from this shared reason. This is endpoint-local unavailability, not rate limiting: retry only this route after Retry-After (or error.retry_at), and do not feed it into a rate-limit backoff shared with other endpoints. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the seconds until it probes Redis again. Both carry error.code=\"rate_limit_unavailable\" (a FROZEN contract value, so it cannot be split per cause) and X-Request-Id -- which is why error.reason, not error.code, is the discriminator.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until retrying is worth doing. With error.reason=\"read_model_warming\" this is the endpoint-local read-model retry interval; without a reason it is the rate-limiter outage cooldown. Always >= 1.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "deprecated": true
      }
    },
    "/api/v1/leaderboard": {
      "get": {
        "operationId": "listLeaderboard",
        "summary": "Get trader leaderboard",
        "description": "Returns ranked traders (grades S/A/B), by default in the board's own order: score descending, with a fixed tiebreak so the order never changes between reads of one ranking generation. sort, dir and activity reorder and scope the same wallets the way the site's leaderboard does (since 2026-11-02, #32237). Supports cursor pagination and optional category/strategy filters. A cursor survives a new ranking generation: the next page continues after its boundary, and meta.continued_from_generation names the cursor's generation when the ranking moved under it, so a trader who crossed the boundary can repeat or be missing. A sorted or activity-scoped page reads the serving projection only; while that projection is older than its 300 s freshness bound it answers 503 rate_limit_unavailable with error.reason read_model_warming and Retry-After, and the default order keeps serving.",
        "tags": ["Leaderboard"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of ranked traders to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque lbv1_ pagination cursor from a prior response. It binds the finite score/address boundary to the effective category/strategy filters, and on a sorted page to its sort, dir and activity, and it names the leaderboard generation it was read at. A cursor from another sort or dir is a 400 bad_request on cursor; one from another activity, category or strategy is cursor_expired. A cursor from an earlier generation continues after its boundary in the current ranking (since 2026-11-07, #33377); meta.continued_from_generation is set when the ranking moved under it. Legacy, malformed, non-finite, and unsupported-version cursors are rejected.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "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).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "strategy",
            "in": "query",
            "description": "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.",
            "schema": {
              "type": "string",
              "enum": [
                "category_focused",
                "diversified",
                "high_activity",
                "mixed",
                "two_sided",
                "unclassified"
              ]
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Order of the list, the sort columns of the site's leaderboard (/skill-leaderboard). rank (default) is the board's own order, the rank the site and the trader profile show. grade orders by score. volume orders by sports and esports USD volume, the figure GET /api/v1/trader/{address} serves as stats.total_volume. predictions orders by markets_traded. pnl orders by in_scope.realized_pnl. win_rate orders by win_rate among wallets with at least 5 decided sports and esports markets; a wallet with fewer sorts as having none. edge orders by price_edge.edge among wallets whose price_edge.status is ranked and that carry no price_edge.hold; any other wallet sorts as having none. The site's Edge column ranks those same wallets by their edge pulled toward the sports and esports average, a figure the API does not send, so the two orders can differ. A wallet without the value sorts as the lowest, so last in the natural direction and first with the direction reversed. Ties fall to address ascending. With ?category= a sort still orders by these whole-record figures; the category only decides which wallets are listed. Since 2026-11-02 (#32237; edge, #32270).",
            "schema": {
              "type": "string",
              "enum": ["rank", "grade", "volume", "predictions", "pnl", "win_rate", "edge"],
              "default": "rank"
            }
          },
          {
            "name": "dir",
            "in": "query",
            "description": "Direction of sort. Omitted, each sort reads in its natural direction: rank 1 first for rank (asc), largest first for every other sort (desc). The opposite value reverses the list. Since 2026-11-02 (#32237).",
            "schema": {
              "type": "string",
              "enum": ["asc", "desc"]
            }
          },
          {
            "name": "activity",
            "in": "query",
            "description": "Limit the list to wallets by recent trading, the site leaderboard's split. active: the wallet's last trade, as its current grade recorded it and aged to today, is 30 days old or less. inactive: older than 30 days, or no trade on record. all (default): every ranked wallet. Since 2026-11-02 (#32237).",
            "schema": {
              "type": "string",
              "enum": ["all", "active", "inactive"],
              "default": "all"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ranked trader list",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Stable validator for the current leaderboard payload. Re-send it via If-None-Match for conditional GETs.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LeaderboardEntry"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total matching rows when the read model exposes a count; the key is absent when it does not."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    },
                    "summary": {
                      "$ref": "#/components/schemas/LeaderboardSummary"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [],
                      "has_more": false,
                      "total": 0,
                      "summary": {
                        "ranked_total": 8300,
                        "by_grade": {
                          "S": 259,
                          "A": 1003,
                          "B": 7038
                        },
                        "active_30d": 4870,
                        "as_of": "2026-11-03T20:57:23Z"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1,
                        "ranking_generation": 42,
                        "ranking_as_of": "2026-08-25T05:00:00Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current leaderboard payload and committed ranking generation.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged leaderboard payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Bad request. On this cursor-paginated route, error.reason=cursor_expired with error.param=cursor means the cursor came from another category, strategy or activity filter; a newer ranking generation alone no longer expires a cursor (since 2026-11-07, #33377). Discard accumulated rows, request the first page again, and continue with its next_cursor. There is no retry delay. Without error.reason, inspect error.param and error.message for an ordinary malformed request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. On this route a 503 has TWO distinct causes; branch on error.reason. (1) error.reason=\"read_model_warming\" (since 2026-11-02, #32290): the leaderboard's serving projection is missing or was last verified 180 s ago or more, so no page can be served at the freshness a 200 states. Its worker normally brings it back within seconds to a few minutes; retry only this route after Retry-After (30 s, or error.retry_at), and do not feed it into a rate-limit backoff shared with other endpoints. Before 2026-11-02 this state answered a 200 computed from the live ranking tables, which could take several seconds. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the seconds until it probes Redis again. Both carry error.code=\"rate_limit_unavailable\" (a FROZEN contract value, so it cannot be split per cause) and X-Request-Id -- which is why error.reason, not error.code, is the discriminator.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until retrying is worth doing. With error.reason=\"read_model_warming\" this is the leaderboard projection's retry interval, 30; without a reason it is the rate-limiter outage cooldown. Always >= 1.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/leaderboard'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/pick-of-the-day": {
      "get": {
        "operationId": "getPickOfTheDay",
        "summary": "Get today's or a past day's Pick of the Day",
        "description": "Returns entitled published picks for the current product day, or for the past product day named by `date`. Pro includes five selections in total: the designated free selection and the first four non-free selections in publication order. Max opens every available selection, up to twenty-five. A day can include multiple selections from the same game. Same-game picks share exposure and need not be independent; retain each `pick_id` instead of deduplicating by game. Both read resolved picks. Publication prices and backing are frozen. Without `date`, a prior day never appears here.\n\nWith `date` (YYYY-MM-DD, America/New_York, before today), the response is that day's slate as the dated web page shows it, under the same tier rule: resolved picks are open to both tiers, and unresolved picks outside the tier appear as `locked_picks`. A past day carries no `scheduled_picks`. A past day with no published pick returns a final 404 `not_found` with `error.param=date` and no retry guidance. Today's date is the same read as no `date`; a date after today returns 400 `bad_request` with `error.param=date`. The archive lists every published pick with its `pick_date`.\n\nStable `pick_id` values identify selections. `publication_order` describes presentation and `is_free_selection` describes access; neither is a quality rating. Standing selections retain their identity, slot, and release schedule. Later additions fill available slots. Historical IDs, order, and proof bytes remain unchanged.\n\nUnauthorized unresolved selections appear only as identity-free `locked_picks` containing `pick_rank` and `required_tier`. When only locked selections are published, HTTP 200 carries `state=none`, `picks=[]`, `pick_count=0`, and an Upgrade to Max message. Proof warming applies only to entitled picks.\n\n`scheduled_picks` contains only entitled slots and retains required `release_at` and `kickoff`. Unauthorized scheduled selections expose no game identity or release time.\n\nFor today, when no active pick is available, including after cancelled recommendations are withdrawn, HTTP 404 carries `error.code=\"not_found\"` and `error.reason=\"pick_not_released\"`. Branch on the reason and schedule one request using `Retry-After` or `error.retry_at` instead of polling. This advisory retry does not reveal an unauthorized game's release time.\n\nFinal sporting scores are retained for resolved picks after the event is confirmed ended and both sides have verified scores. A result without a verified final stays unavailable; a win/loss outcome alone does not establish a sporting score. Existing sports_context fields and return calculations are unchanged.\n\nWithdrawn picks are excluded from current and dated recommendations, the archive, and its statistics, even after market settlement. The public ledger retains every published commitment under its original identity and proof bytes. Provider settlement still determines the recorded result. Request and response fields are unchanged.\n\n`view=summary` returns each entitled pick's identity, side, price, result, return and grade, about 600 bytes a pick, and `pick_id` narrows the set to one pick; together they read a slate, then one pick's whole record (holders, sports context, `entry_authorization`). The default `view=full` and a request without `pick_id` are unchanged. The full set of 2026-11-02 (14 picks) was 198,807 bytes, past the 50,000 characters an MCP client such as Claude Code shows of a tool result, so the MCP tool defaults to the summary.",
        "tags": ["Pick of the Day"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "date",
            "in": "query",
            "required": false,
            "description": "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.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "view",
            "in": "query",
            "required": false,
            "description": "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.",
            "schema": {
              "type": "string",
              "enum": ["full", "summary"],
              "default": "full"
            }
          },
          {
            "name": "pick_id",
            "in": "query",
            "required": false,
            "description": "One entitled published pick of the day, by its stable decimal-string pick_id. The body carries that pick once, as picks[0], beside state, pick_date and pick_count=1. It leaves out the top-level copy of the first pick that a set read without pick_id repeats, and scheduled_picks, proof_pending_picks and 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.",
            "schema": {
              "type": "string",
              "pattern": "^[1-9][0-9]*$"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The entitled Pick of the Day slate for today, or for the past day named by `date`, or an identity-free locked response when no entitled picks are published.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Stable validator for the current Pick of the Day payload. Re-send it via If-None-Match for conditional GETs.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "pick_of_the_day"
                    },
                    "data": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/PickOfTheDay"
                        },
                        {
                          "$ref": "#/components/schemas/PickOfTheDayNoEntitledPicks"
                        },
                        {
                          "type": "object",
                          "required": ["view", "state", "pick_date", "pick_count", "picks"],
                          "properties": {
                            "disclaimer": {
                              "type": "string"
                            },
                            "locked_picks": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "required": ["pick_rank", "required_tier"],
                                "properties": {
                                  "pick_rank": {
                                    "type": "integer"
                                  },
                                  "required_tier": {
                                    "type": "string"
                                  }
                                }
                              }
                            },
                            "pick_count": {
                              "type": "integer"
                            },
                            "pick_date": {
                              "type": "string",
                              "format": "date"
                            },
                            "picks": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "required": ["pick_id", "publication_order", "is_free_selection"],
                                "properties": {
                                  "backed_price": {
                                    "type": "number"
                                  },
                                  "category": {
                                    "type": "string"
                                  },
                                  "clv_pct": {
                                    "type": "number"
                                  },
                                  "clv_status": {
                                    "type": "string"
                                  },
                                  "display_category": {
                                    "type": "string"
                                  },
                                  "event_slug": {
                                    "type": "string"
                                  },
                                  "game_ended": {
                                    "type": "boolean"
                                  },
                                  "game_started": {
                                    "type": "boolean"
                                  },
                                  "holder_count": {
                                    "type": "integer"
                                  },
                                  "is_free_selection": {
                                    "type": "boolean"
                                  },
                                  "matchup": {
                                    "type": "string"
                                  },
                                  "outcome": {
                                    "type": "string"
                                  },
                                  "pick_id": {
                                    "type": "string"
                                  },
                                  "pick_outcome_label": {
                                    "type": "string"
                                  },
                                  "polymarket_url": {
                                    "type": "string"
                                  },
                                  "publication_order": {
                                    "type": "integer"
                                  },
                                  "release_at": {
                                    "type": "string",
                                    "format": "date-time"
                                  },
                                  "return_usd": {
                                    "type": "number"
                                  },
                                  "stake_usd": {
                                    "type": "number"
                                  },
                                  "token_id": {
                                    "type": "string"
                                  },
                                  "top_grade": {
                                    "type": "string"
                                  },
                                  "unit_score": {
                                    "type": "number"
                                  }
                                }
                              }
                            },
                            "proof_pending_picks": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "required": [
                                  "pick_id",
                                  "publication_order",
                                  "is_free_selection",
                                  "supersedes_pick_id",
                                  "pick_rank",
                                  "release_at",
                                  "retry_at"
                                ],
                                "properties": {
                                  "is_free_selection": {
                                    "type": "boolean"
                                  },
                                  "kickoff": {
                                    "type": "string",
                                    "format": "date-time"
                                  },
                                  "pick_id": {
                                    "type": "string"
                                  },
                                  "pick_rank": {
                                    "type": "integer"
                                  },
                                  "publication_order": {
                                    "type": "integer"
                                  },
                                  "release_at": {
                                    "type": "string",
                                    "format": "date-time"
                                  },
                                  "retry_at": {
                                    "type": "string",
                                    "format": "date-time"
                                  },
                                  "supersedes_pick_id": {
                                    "type": ["string", "null"]
                                  }
                                }
                              }
                            },
                            "scheduled_picks": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "required": [
                                  "pick_id",
                                  "publication_order",
                                  "is_free_selection",
                                  "supersedes_pick_id",
                                  "pick_rank",
                                  "release_at",
                                  "kickoff"
                                ],
                                "properties": {
                                  "is_free_selection": {
                                    "type": "boolean"
                                  },
                                  "kickoff": {
                                    "type": "string",
                                    "format": "date-time"
                                  },
                                  "pick_id": {
                                    "type": "string"
                                  },
                                  "pick_rank": {
                                    "type": "integer"
                                  },
                                  "publication_order": {
                                    "type": "integer"
                                  },
                                  "release_at": {
                                    "type": "string",
                                    "format": "date-time"
                                  },
                                  "supersedes_pick_id": {
                                    "type": ["string", "null"]
                                  }
                                }
                              }
                            },
                            "state": {
                              "type": "string"
                            },
                            "view": {
                              "type": "string"
                            }
                          }
                        }
                      ]
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Published pick whose selector recorded no qualifying category expert -- a real negative, confirmed by trust",
                    "value": {
                      "object": "pick_of_the_day",
                      "data": {
                        "state": "full",
                        "pick_date": "2026-06-23",
                        "matchup": "Portugal vs. Uzbekistan",
                        "category": "Soccer",
                        "display_category": "Soccer",
                        "platform": "polymarket",
                        "release_at": "2026-06-23T17:00:00Z",
                        "is_locked": false,
                        "outcome": "pending",
                        "pick_outcome_label": "Portugal",
                        "position": "Portugal to win",
                        "side_summary": "1 profitable wallet on Portugal",
                        "sharp_wallet_count": 1,
                        "smart_wallet_count": 1,
                        "top_grade": "A",
                        "sharp_usd": 48250,
                        "smart_usd": 48250,
                        "backed_price": 0.62,
                        "stake_usd": 1000,
                        "return_usd": 1612.9,
                        "return_per_100": 161.29,
                        "clv_status": "pending",
                        "market_pct": 0.62,
                        "traders": 1,
                        "holders": [
                          {
                            "address": "0x0000000000000000000000000000000000000000",
                            "name": "swisstony",
                            "grade": "A",
                            "last_traded_at": "2026-06-18T17:42:10Z",
                            "shares": 12500
                          }
                        ],
                        "display_holders": [
                          {
                            "address": "0x0000000000000000000000000000000000000000",
                            "name": "swisstony",
                            "grade": "A",
                            "last_traded_at": "2026-06-18T17:42:10Z",
                            "shares": 12500,
                            "category_win_rate": 0.64,
                            "category_win_record": {
                              "wins": 16,
                              "decided": 25
                            },
                            "category_win_rate_status": "measured"
                          },
                          {
                            "address": "0x1111111111111111111111111111111111111111",
                            "name": "marketmaker",
                            "grade": "B",
                            "last_traded_at": "2026-06-18T17:42:10Z",
                            "shares": 9800,
                            "category_win_rate_status": "not_enough_data"
                          }
                        ],
                        "holder_count": 1,
                        "thesis": "Profitable wallets hold Portugal, led by a grade-A trader.",
                        "market_url": "https://0xinsider.com/event/portugal-vs-uzbekistan",
                        "event_slug": "portugal-vs-uzbekistan",
                        "event_link_slug": "portugal-vs-uzbekistan",
                        "sports_context": {
                          "league_name": "FIFA World Cup",
                          "league_logo": "https://polymarket.com/leagues/fifa-world-cup.png",
                          "yes_team": {
                            "label": "Portugal",
                            "short_label": "POR",
                            "full_name": "Portugal",
                            "provider_id": 1421,
                            "logo": "https://polymarket.com/teams/portugal.png",
                            "logo_mark_dark": false,
                            "logo_mark_light": false,
                            "logo_mark_measured": false,
                            "color": "#C8102E",
                            "record": null,
                            "score": null
                          },
                          "no_team": {
                            "label": "Uzbekistan",
                            "short_label": "UZB",
                            "full_name": "Uzbekistan",
                            "provider_id": 1738,
                            "logo": "https://polymarket.com/teams/uzbekistan.png",
                            "logo_mark_dark": false,
                            "logo_mark_light": false,
                            "logo_mark_measured": false,
                            "color": "#1EB53A",
                            "record": null,
                            "score": null
                          },
                          "game_id": 884213,
                          "event_matchup": false,
                          "matchup_title": "Portugal – Uzbekistan"
                        },
                        "disclaimer": "Not financial advice. Prediction markets carry risk; do your own research.",
                        "pick_id": "1000",
                        "publication_order": 1,
                        "is_free_selection": true,
                        "supersedes_pick_id": null
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current Pick of the Day payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged Pick of the Day payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid date. A value that is not YYYY-MM-DD, or a date after the current product day (America/New_York), returns 400 bad_request with error.param=date.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Without `date`: no Pick of the Day is published for the current product day, which uses America/New_York. Explicitly scheduled selections retain their returned release time. The body carries error.code=\"not_found\", error.reason=\"pick_not_released\", and error.retry_at (RFC3339, always in the future); the response also sets Retry-After. Branch on the reason and schedule the next request from the returned retry guidance instead of polling. With a past `date`: no pick was published that day, or every pick that day was withdrawn. The body carries error.code=\"not_found\" and error.param=\"date\", with no reason, retry_at or Retry-After: a past day does not change, so do not retry it.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the recommended next request, always at least 1. This names the same instant as error.retry_at. The recommendation is advisory and can change. Schedule one request using the returned guidance rather than inferring a release schedule; prefer this relative duration to avoid client clock skew.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. On this route a 503 has TWO distinct causes; branch on error.reason. (1) error.reason=\"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; consult that endpoint's contract and do not infer dependency health from this shared reason. This is endpoint-local unavailability, not rate limiting: retry only this route after Retry-After (or error.retry_at), and do not feed it into a rate-limit backoff shared with other endpoints. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the seconds until it probes Redis again. Both carry error.code=\"rate_limit_unavailable\" (a FROZEN contract value, so it cannot be split per cause) and X-Request-Id -- which is why error.reason, not error.code, is the discriminator.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until retrying is worth doing. With error.reason=\"read_model_warming\" this is the endpoint-local read-model retry interval; without a reason it is the rate-limiter outage cooldown. Always >= 1.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/pick-of-the-day'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "pick_of_the_day",
            "data": {
              "state": "full",
              "pick_date": "2026-06-23",
              "matchup": "Portugal vs. Uzbekistan",
              "category": "Soccer",
              "display_category": "Soccer",
              "platform": "polymarket",
              "release_at": "2026-06-23T17:00:00Z",
              "is_locked": false,
              "outcome": "pending",
              "pick_outcome_label": "Portugal",
              "position": "Portugal to win",
              "side_summary": "1 profitable wallet on Portugal",
              "sharp_wallet_count": 1,
              "smart_wallet_count": 1,
              "top_grade": "A",
              "sharp_usd": 48250,
              "smart_usd": 48250,
              "backed_price": 0.62,
              "stake_usd": 1000,
              "return_usd": 1612.9,
              "return_per_100": 161.29,
              "clv_status": "pending",
              "market_pct": 0.62,
              "traders": 1,
              "holders": [
                {
                  "address": "0x0000000000000000000000000000000000000000",
                  "name": "swisstony",
                  "grade": "A",
                  "shares": 12500
                }
              ],
              "display_holders": [
                {
                  "address": "0x0000000000000000000000000000000000000000",
                  "name": "swisstony",
                  "grade": "A",
                  "shares": 12500,
                  "category_win_rate": 0.64,
                  "category_win_record": {
                    "wins": 16,
                    "decided": 25
                  },
                  "category_win_rate_status": "measured"
                },
                {
                  "address": "0x1111111111111111111111111111111111111111",
                  "name": "marketmaker",
                  "grade": "B",
                  "shares": 9800,
                  "category_win_rate": null,
                  "category_win_rate_status": "not_enough_data"
                }
              ],
              "holder_count": 1,
              "thesis": "Profitable wallets hold Portugal, led by a grade-A trader.",
              "market_url": "https://0xinsider.com/event/portugal-vs-uzbekistan",
              "event_slug": "portugal-vs-uzbekistan",
              "event_link_slug": "portugal-vs-uzbekistan",
              "sports_context": {
                "league_name": "FIFA World Cup",
                "league_logo": "https://polymarket.com/leagues/fifa-world-cup.png",
                "yes_team": {
                  "label": "Portugal",
                  "short_label": "POR",
                  "full_name": "Portugal",
                  "provider_id": 1421,
                  "logo": "https://polymarket.com/teams/portugal.png",
                  "color": "#C8102E",
                  "record": null,
                  "score": null
                },
                "no_team": {
                  "label": "Uzbekistan",
                  "short_label": "UZB",
                  "full_name": "Uzbekistan",
                  "provider_id": 1738,
                  "logo": "https://polymarket.com/teams/uzbekistan.png",
                  "color": "#1EB53A",
                  "record": null,
                  "score": null
                },
                "game_id": 884213,
                "event_matchup": false,
                "matchup_title": "Portugal – Uzbekistan"
              },
              "disclaimer": "Not financial advice. Prediction markets carry risk; do your own research."
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/pick-of-the-day/archive": {
      "get": {
        "operationId": "getPickOfTheDayArchive",
        "summary": "Get the Pick of the Day track record",
        "description": "Returns published picks that have not been withdrawn, with their outcome, modeled return, unit score, closing-line value, and cumulative record. Resolved game details and results are public. For unauthorized unresolved selections, game identity, category, image, publication time, and backed facts are omitted; `required_tier` and `backed_side_locked` provide an upgrade action. Pro includes the designated free selection and the first four non-free selections in publication order, five in total. Max opens every available selection, up to twenty-five.\n\nStable `pick_id` values identify selections. Historical picks retain their original IDs, order, and proof bytes. `publication_order` describes presentation and `is_free_selection` records access designation; neither is a quality rating. New selections use a neutral presentation order, while standing selections retain their identity, slot, and release schedule.\n\nEach row carries measured CLV or the reason it was not measured. Coverage is the share of resolved picks published before kickoff that have measured CLV. A post-kickoff publication is `not_applicable`.\n\nWithdrawn recommendations are excluded from archive rows, daily counts, and all track-record statistics, including CLV, financial aggregates, and the cumulative series. Later market settlement does not restore them to the archive. The public ledger retains every published commitment under its original pick_id and proof bytes. Request and response fields are unchanged.\n\n`view=summary` returns the headline record (`hit_rate` without its per-pick `series`) and one page of short rows; `limit` and `cursor` page `picks` in either view and add `page` (`limit`, `returned`, `total`, `has_more`, `next_cursor`). A request with none of the three is the whole record, unchanged: 1,124,089 bytes for 888 picks on 2026-11-03. The MCP tool defaults to the summary.",
        "tags": ["Pick of the Day"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "view",
            "in": "query",
            "required": false,
            "description": "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.",
            "schema": {
              "type": "string",
              "enum": ["full", "summary"],
              "default": "full"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "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.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 50,
              "maximum": 200
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "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.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pick of the Day track record",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Stable validator for the current Pick of the Day archive payload. Re-send it via If-None-Match for conditional GETs.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "pick_of_the_day_archive"
                    },
                    "data": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/PickOfTheDayArchive"
                        },
                        {
                          "$ref": "#/components/schemas/PickOfTheDayArchiveSummary"
                        }
                      ]
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "pick_of_the_day_archive",
                      "data": {
                        "picks": [
                          {
                            "pick_date": "2026-06-23",
                            "pick_rank": 1,
                            "published_at": "2026-06-23T15:30:00Z",
                            "matchup": "Portugal vs. Uzbekistan",
                            "category": "Soccer",
                            "display_category": "Soccer",
                            "pick_outcome_label": "Portugal",
                            "top_grade": "A",
                            "outcome": "pending",
                            "clv_status": "pending",
                            "pick_id": "1000",
                            "publication_order": 1,
                            "is_free_selection": true,
                            "supersedes_pick_id": null
                          },
                          {
                            "pick_date": "2026-06-22",
                            "pick_rank": 2,
                            "published_at": "2026-06-22T15:30:00Z",
                            "matchup": "Spain vs. France",
                            "category": "Soccer",
                            "display_category": "Soccer",
                            "image_url": "https://polymarket-upload.s3.us-east-2.amazonaws.com/soccer%20ball-bba4025f77.png",
                            "pick_outcome_label": "Spain",
                            "top_grade": "A",
                            "outcome": "win",
                            "resolved_at": "2026-06-22T22:10:00Z",
                            "stake_usd": 1000,
                            "return_usd": 2000,
                            "return_per_100": 200,
                            "payout_display": "$2,000.00",
                            "backed_price": 0.5,
                            "unit_score": 1,
                            "unit_score_display": "+1.00u",
                            "clv_status": "measured",
                            "clv_pct": 10,
                            "clv_display": "+10.0%",
                            "clv_applicability": "applicable",
                            "clv_explanation": "CLV = (0.55 / 0.5 - 1) x 100 = +10.0%.\nEntry is the stored pick probability. Close is the last valid Polymarket probability before kickoff.\nThe result and payout do not affect CLV.",
                            "pick_id": "1001",
                            "publication_order": 2,
                            "is_free_selection": false,
                            "supersedes_pick_id": null
                          }
                        ],
                        "hit_rate": {
                          "wins": 1,
                          "losses": 0,
                          "decided": 1,
                          "pct": 100,
                          "void": 0,
                          "pending": 1,
                          "stake_usd": 1000,
                          "net_profit_usd": 1000,
                          "staked_usd": 1000,
                          "roi_pct": 100,
                          "net_profit_display": "+$1,000",
                          "roi_display": "+100.0%",
                          "win_rate_display": "100.0%",
                          "series": [
                            {
                              "date": "2026-06-22",
                              "net_profit_usd": 1000,
                              "hit_rate_pct": 100
                            }
                          ],
                          "clv_eligible": 1,
                          "clv_total": 1,
                          "clv_measured": 1,
                          "clv_applicable": 1,
                          "clv_not_applicable": 0,
                          "clv_pending": 0,
                          "clv_unavailable": 0,
                          "clv_state": "measured",
                          "clv_beats_close": 1,
                          "clv_ties": 0
                        },
                        "days": [
                          {
                            "date": "2026-06-23",
                            "picks": 1,
                            "wins": 0,
                            "losses": 0,
                            "void": 0,
                            "pending": 1
                          },
                          {
                            "date": "2026-06-22",
                            "picks": 1,
                            "wins": 1,
                            "losses": 0,
                            "void": 0,
                            "pending": 0,
                            "unit_score": 0.55,
                            "unit_score_display": "+0.55u",
                            "sweep": "win"
                          }
                        ]
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current Pick of the Day archive payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged Pick of the Day archive payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/pick-of-the-day/archive'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/pick-of-the-day/stats": {
      "get": {
        "operationId": "getPickOfTheDayStats",
        "summary": "Get the Pick of the Day track-record breakdown",
        "description": "The figures behind the stats page, computed from the same rows the archive publishes: the hit rate, the win rate the market expected at publication, flat-stake outcome stats (drawdown, rolling form, profit factor, concentration), and buckets by day, sport, category, access group, month, entry-price band, market type and totals side, plus streaks, records and every void pick. Withdrawn picks are outside every figure, as in the archive. Pro reads the Pro view; Max counts every selection whose backed side Max sees.\n\n`view=summary` drops the five sections that grow with the record (`series`, `days`, `categories`, `months` and `voids`; the first four were 127,020 of the 151,774 bytes on 2026-11-03), and `sections` returns exactly the sections named, `series` among them as its own top-level key. Both add `view` and `sections` to the body; the default `view=full` body is unchanged. The MCP tool defaults to the summary.",
        "tags": ["Pick of the Day"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "view",
            "in": "query",
            "required": false,
            "description": "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.",
            "schema": {
              "type": "string",
              "enum": ["full", "summary"],
              "default": "full"
            }
          },
          {
            "name": "sections",
            "in": "query",
            "required": false,
            "description": "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.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "hit_rate",
                  "series",
                  "market_expectations",
                  "outcome_stats",
                  "days",
                  "categories",
                  "sports",
                  "tiers",
                  "months",
                  "price_bands",
                  "market_types",
                  "total_sides",
                  "streaks",
                  "records",
                  "voids"
                ]
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "sections[]",
            "in": "query",
            "required": false,
            "description": "Backward-compatible bracket alias for sections, for clients that emit array keys. Repeatable and comma-separated, with the same names.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "hit_rate",
                  "series",
                  "market_expectations",
                  "outcome_stats",
                  "days",
                  "categories",
                  "sports",
                  "tiers",
                  "months",
                  "price_bands",
                  "market_types",
                  "total_sides",
                  "streaks",
                  "records",
                  "voids"
                ]
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pick of the Day track-record breakdown",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Stable validator for the current stats payload. Re-send it via If-None-Match for conditional GETs.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "pick_of_the_day_stats"
                    },
                    "data": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/PickOfTheDayStats"
                        },
                        {
                          "$ref": "#/components/schemas/PickOfTheDayStatsSections"
                        }
                      ]
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "pick_of_the_day_stats",
                      "data": {
                        "voids": [
                          {
                            "pick_id": "1730",
                            "pick_date": "2026-10-19",
                            "pick_rank": 7,
                            "matchup": "Japan Women's Open: Sonay Kartal vs Kimberly Birrell",
                            "category": "WTA",
                            "backed_side": "Kimberly Birrell (-1.5)",
                            "backed_price": 0.505
                          }
                        ],
                        "hit_rate": {
                          "wins": 508,
                          "losses": 352,
                          "decided": 860,
                          "pct": 59.1,
                          "void": 3,
                          "pending": 4,
                          "stake_usd": 1000.0,
                          "net_profit_usd": 21725.413191940002,
                          "staked_usd": 860000.0,
                          "roi_pct": 2.5,
                          "net_profit_display": "+$21,725",
                          "roi_display": "+2.5%",
                          "win_rate_display": "59.1%",
                          "series": [
                            {
                              "date": "2026-06-24",
                              "net_profit_usd": 980.1980198019801,
                              "hit_rate_pct": 100.0
                            }
                          ],
                          "unit_score": 21.725413191940056,
                          "unit_score_display": "+21.73u",
                          "clv_eligible": 862,
                          "clv_total": 863,
                          "clv_measured": 855,
                          "clv_applicable": 863,
                          "clv_not_applicable": 0,
                          "clv_pending": 0,
                          "clv_unavailable": 8,
                          "clv_state": "measured",
                          "clv_coverage_pct": 99.07300115874855,
                          "clv_coverage_display": "99.1%",
                          "clv_coverage_explanation": "CLV covers 855 of 863 picks published before kickoff.",
                          "clv_avg_pct": -0.15982926018937388,
                          "clv_avg_display": "-0.2%",
                          "clv_avg_pp": -0.10438596491228073,
                          "clv_avg_pp_display": "-0.1 pp",
                          "clv_beats_close": 286,
                          "clv_ties": 260
                        },
                        "market_expectations": {
                          "as_of_date": "2026-11-01",
                          "timezone": "America/New_York",
                          "price_basis": "frozen_provider_entry_price",
                          "windows": [
                            {
                              "key": "all_time",
                              "label": "All time",
                              "from_date": "2026-06-24",
                              "through_date": "2026-11-01",
                              "priced_decided": 860,
                              "unpriced_decided": 0,
                              "wins": 508,
                              "expected_wins": 497.1402499999998,
                              "expected_wins_display": "497.1",
                              "units": 21.725413191940007,
                              "units_display": "+21.73u",
                              "wins_z": null,
                              "wins_z_display": null,
                              "units_z": null,
                              "units_z_display": null,
                              "clv_measured": 853,
                              "clv_missing": 7,
                              "clv_avg_pct": -0.14856164508343686,
                              "clv_avg_display": "-0.1%",
                              "clv_avg_pp": -0.09642438452520516,
                              "clv_avg_pp_display": "-0.1 pp",
                              "numeric_unavailable": true
                            }
                          ]
                        },
                        "outcome_stats": {
                          "drawdown": {
                            "completed_days": 129,
                            "excluded_days": 1,
                            "from_date": "2026-06-24",
                            "through_date": "2026-10-31",
                            "max_drawdown_units": 20.639258616960085,
                            "max_drawdown_display": "20.64u",
                            "current_drawdown_units": 18.118384216765175,
                            "current_drawdown_display": "18.12u",
                            "days_below_peak": 96,
                            "longest_days_below_peak": 40,
                            "current_days_below_peak": 8,
                            "longest_recovery_days": 41,
                            "peak_date": "2026-10-23",
                            "peak_net_profit_usd": 39936.922711545565
                          },
                          "rolling": [
                            {
                              "window_size": 20,
                              "valued_decided": 20,
                              "wins": 11,
                              "losses": 9,
                              "from_date": "2026-10-31",
                              "through_date": "2026-11-01",
                              "units": 0.9889323874647376,
                              "units_display": "+0.99u",
                              "roi_pct": 4.944661937323688,
                              "roi_display": "+4.9%",
                              "win_rate_pct": 55.00000000000001,
                              "win_rate_display": "55.0%"
                            }
                          ],
                          "profit_factor": {
                            "valued_decided": 860,
                            "state": "measured",
                            "gross_profit_usd": 373725.41319193924,
                            "gross_loss_usd": 352000.0,
                            "value": 1.0617199238407364,
                            "display": "1.06"
                          },
                          "concentration": {
                            "valued_decided": 860,
                            "positive_wins": 508,
                            "removed_wins": 5,
                            "target_wins": 5,
                            "top_wins_share_pct": 3.00048899130792,
                            "top_wins_share_display": "3.0%",
                            "remaining_valued_decided": 855,
                            "roi_without_top_wins_pct": 1.2294530188767054,
                            "roi_without_top_wins_display": "+1.2%"
                          }
                        },
                        "days": [
                          {
                            "date": "2026-06-24",
                            "picks": 1,
                            "wins": 1,
                            "losses": 0,
                            "void": 0,
                            "pending": 0,
                            "net_profit_usd": 980.1980198019801,
                            "net_profit_display": "+$980",
                            "unit_score": 0.9801980198019802,
                            "unit_score_display": "+0.98u"
                          }
                        ],
                        "categories": [
                          {
                            "key": "MLB",
                            "label": "MLB",
                            "canonical_category": "Baseball",
                            "picks": 85,
                            "wins": 49,
                            "losses": 36,
                            "void": 0,
                            "pending": 0,
                            "settled": 85,
                            "win_rate_pct": 57.6,
                            "win_rate_display": "57.6%",
                            "priced_decided": 85,
                            "priced_in_pct": 52.547058823529426,
                            "priced_in_display": "52.5%",
                            "edge_pp": 5.09999999999998,
                            "edge_display": "+5.1 pp",
                            "small_sample": false,
                            "staked_usd": 85000.0,
                            "net_profit_usd": 7872.753386623983,
                            "net_profit_display": "+$7,873",
                            "roi_pct": 9.3,
                            "roi_display": "+9.3%",
                            "unit_score": 7.872753386623982,
                            "unit_score_display": "+7.87u",
                            "clv_measured": 84,
                            "clv_avg_pct": 0.21770750834237326,
                            "clv_avg_display": "+0.2%",
                            "clv_avg_pp": 0.1309523809523809,
                            "clv_avg_pp_display": "+0.1 pp"
                          }
                        ],
                        "sports": [
                          {
                            "key": "Soccer",
                            "label": "Soccer",
                            "canonical_category": "Soccer",
                            "picks": 335,
                            "wins": 200,
                            "losses": 133,
                            "void": 1,
                            "pending": 1,
                            "settled": 333,
                            "win_rate_pct": 60.1,
                            "win_rate_display": "60.1%",
                            "priced_decided": 333,
                            "priced_in_pct": 58.902177177177215,
                            "priced_in_display": "58.9%",
                            "edge_pp": 1.157882882882845,
                            "edge_display": "+1.2 pp",
                            "small_sample": false,
                            "staked_usd": 333000.0,
                            "net_profit_usd": 7931.224126486872,
                            "net_profit_display": "+$7,931",
                            "roi_pct": 2.4,
                            "roi_display": "+2.4%",
                            "unit_score": 7.9312241264868675,
                            "unit_score_display": "+7.93u",
                            "clv_measured": 334,
                            "clv_avg_pct": -0.08803505970231479,
                            "clv_avg_display": "-0.1%",
                            "clv_avg_pp": -0.09745508982035912,
                            "clv_avg_pp_display": "-0.1 pp"
                          }
                        ],
                        "tiers": [
                          {
                            "key": "free",
                            "label": "Free",
                            "picks": 127,
                            "wins": 81,
                            "losses": 46,
                            "void": 0,
                            "pending": 0,
                            "settled": 127,
                            "win_rate_pct": 63.8,
                            "win_rate_display": "63.8%",
                            "priced_decided": 127,
                            "priced_in_pct": 60.45964566929136,
                            "priced_in_display": "60.5%",
                            "edge_pp": 3.3198818897637565,
                            "edge_display": "+3.3 pp",
                            "small_sample": false,
                            "staked_usd": 127000.0,
                            "net_profit_usd": 7719.430231682691,
                            "net_profit_display": "+$7,719",
                            "roi_pct": 6.1,
                            "roi_display": "+6.1%",
                            "unit_score": 7.719430231682702,
                            "unit_score_display": "+7.72u",
                            "clv_measured": 126,
                            "clv_avg_pct": -0.3245278586450475,
                            "clv_avg_display": "-0.3%",
                            "clv_avg_pp": -0.1511904761904764,
                            "clv_avg_pp_display": "-0.2 pp"
                          }
                        ],
                        "months": [
                          {
                            "key": "2026-06",
                            "label": "Jun 2026",
                            "picks": 6,
                            "wins": 5,
                            "losses": 1,
                            "void": 0,
                            "pending": 0,
                            "settled": 6,
                            "win_rate_pct": 83.3,
                            "win_rate_display": "83.3%",
                            "priced_decided": 6,
                            "priced_in_pct": 53.5,
                            "priced_in_display": "53.5%",
                            "edge_pp": 29.833333333333343,
                            "edge_display": "+29.8 pp",
                            "small_sample": true,
                            "staked_usd": 6000.0,
                            "net_profit_usd": 3585.305614320303,
                            "net_profit_display": "+$3,585",
                            "roi_pct": 59.8,
                            "roi_display": "+59.8%",
                            "unit_score": 3.585305614320303,
                            "unit_score_display": "+3.59u",
                            "clv_measured": 6,
                            "clv_avg_pct": 1.787460709884762,
                            "clv_avg_display": "+1.8%",
                            "clv_avg_pp": 0.6666666666666655,
                            "clv_avg_pp_display": "+0.7 pp"
                          }
                        ],
                        "price_bands": [
                          {
                            "key": "under_35",
                            "label": "Longshot (<35c)",
                            "picks": 12,
                            "wins": 6,
                            "losses": 6,
                            "void": 0,
                            "pending": 0,
                            "settled": 12,
                            "win_rate_pct": 50.0,
                            "win_rate_display": "50.0%",
                            "priced_decided": 12,
                            "priced_in_pct": 31.08333333333333,
                            "priced_in_display": "31.1%",
                            "edge_pp": 18.91666666666667,
                            "edge_display": "+18.9 pp",
                            "small_sample": true,
                            "staked_usd": 12000.0,
                            "net_profit_usd": 7198.664507409823,
                            "net_profit_display": "+$7,199",
                            "roi_pct": 60.0,
                            "roi_display": "+60.0%",
                            "unit_score": 7.198664507409822,
                            "unit_score_display": "+7.20u",
                            "clv_measured": 12,
                            "clv_avg_pct": -2.052665499703698,
                            "clv_avg_display": "-2.1%",
                            "clv_avg_pp": -0.5833333333333334,
                            "clv_avg_pp_display": "-0.6 pp"
                          }
                        ],
                        "market_types": [
                          {
                            "key": "moneyline",
                            "label": "Moneyline",
                            "picks": 518,
                            "wins": 319,
                            "losses": 197,
                            "void": 1,
                            "pending": 1,
                            "settled": 516,
                            "win_rate_pct": 61.8,
                            "win_rate_display": "61.8%",
                            "priced_decided": 516,
                            "priced_in_pct": 60.05251937984495,
                            "priced_in_display": "60.1%",
                            "edge_pp": 1.769186046511635,
                            "edge_display": "+1.8 pp",
                            "small_sample": false,
                            "staked_usd": 516000.0,
                            "net_profit_usd": 16066.598401358147,
                            "net_profit_display": "+$16,067",
                            "roi_pct": 3.1,
                            "roi_display": "+3.1%",
                            "unit_score": 16.06659840135815,
                            "unit_score_display": "+16.07u",
                            "clv_measured": 511,
                            "clv_avg_pct": -0.3582518395950433,
                            "clv_avg_display": "-0.4%",
                            "clv_avg_pp": -0.20097847358121337,
                            "clv_avg_pp_display": "-0.2 pp"
                          }
                        ],
                        "total_sides": [
                          {
                            "key": "over",
                            "label": "Over",
                            "picks": 104,
                            "wins": 60,
                            "losses": 43,
                            "void": 0,
                            "pending": 1,
                            "settled": 103,
                            "win_rate_pct": 58.3,
                            "win_rate_display": "58.3%",
                            "priced_decided": 103,
                            "priced_in_pct": 52.15533980582524,
                            "priced_in_display": "52.2%",
                            "edge_pp": 6.097087378640772,
                            "edge_display": "+6.1 pp",
                            "small_sample": false,
                            "staked_usd": 103000.0,
                            "net_profit_usd": 13477.09981886233,
                            "net_profit_display": "+$13,477",
                            "roi_pct": 13.1,
                            "roi_display": "+13.1%",
                            "unit_score": 13.477099818862323,
                            "unit_score_display": "+13.48u",
                            "clv_measured": 103,
                            "clv_avg_pct": -0.3162902037509423,
                            "clv_avg_display": "-0.3%",
                            "clv_avg_pp": -0.22330097087378664,
                            "clv_avg_pp_display": "-0.2 pp"
                          }
                        ],
                        "streaks": {
                          "current": 1,
                          "current_display": "W1",
                          "longest_win": 10,
                          "longest_loss": 6,
                          "current_day": -1,
                          "current_day_display": "L1"
                        },
                        "records": {
                          "biggest_win": {
                            "date": "2026-09-29",
                            "date_display": "Sep 29, 2026",
                            "matchup": "Mexico vs. Peru",
                            "category": "FIFA Friendlies",
                            "net_profit_usd": 2508.7719298245615,
                            "net_profit_display": "+$2,509"
                          },
                          "best_day": {
                            "date": "2026-10-21",
                            "date_display": "Oct 21, 2026",
                            "picks": 20,
                            "wins": 14,
                            "losses": 6,
                            "net_profit_usd": 6034.580382823844,
                            "net_profit_display": "+$6,035"
                          },
                          "worst_day": {
                            "date": "2026-10-26",
                            "date_display": "Oct 26, 2026",
                            "picks": 25,
                            "wins": 7,
                            "losses": 18,
                            "net_profit_usd": -12683.636635069432,
                            "net_profit_display": "-$12,684"
                          },
                          "longest_winning_day_streak": {
                            "days": 10,
                            "start_date": "2026-09-18",
                            "end_date": "2026-09-27",
                            "range_display": "Sep 18-27, 2026",
                            "net_profit_usd": 15530.960075392033,
                            "net_profit_display": "+$15,531"
                          },
                          "longest_losing_day_streak": {
                            "days": 9,
                            "start_date": "2026-09-01",
                            "end_date": "2026-09-09",
                            "range_display": "Sep 1-9, 2026",
                            "net_profit_usd": -13237.648860315225,
                            "net_profit_display": "-$13,238"
                          },
                          "winning_days": {
                            "winning": 78,
                            "losing": 51,
                            "flat": 0,
                            "settled": 129,
                            "winning_pct": 60.46511627906976,
                            "winning_pct_display": "60.5%"
                          },
                          "sweeps": {
                            "min_decided": 3,
                            "clean_sweeps": 5,
                            "wipeouts": 0,
                            "latest_clean_sweep": {
                              "date": "2026-09-18",
                              "date_display": "Sep 18, 2026",
                              "wins": 6,
                              "losses": 0
                            }
                          }
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current Pick of the Day archive payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged Pick of the Day archive payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/pick-of-the-day/stats'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/pick-of-the-day/ledger": {
      "get": {
        "operationId": "getPickOfTheDayLedger",
        "summary": "Get the Pick of the Day commitment ledger",
        "description": "Returns the pre-game commitment for every published pick, so the public track record can be checked by someone who was not watching when the pick dropped.\n\nOne entry per (pick_date, pick_rank), ascending by pick_date then pick_rank, in one of three states. `sealed` is an unresolved pick: the hash, the algorithm, the seal instant, and nothing that states a side or a price. `opened` is a settled pick: the nonce and the exact canonical payload the hash was taken over. `uncommitted` is a pick with no commitment -- published before the scheme existed, or one that reached kickoff unsealed -- named rather than omitted.\n\nTo verify an opened entry: serialize nothing. Take the bytes of the `payload` object exactly as received, append the `commitment_nonce` decoded from hex, and sha256 the result; it equals `commitment_hash`. The payload is canonical JSON -- keys sorted by UTF-8 byte value, no insignificant whitespace, decimals as strings at full stored precision, timestamps whole-second UTC with a literal Z -- and it is served byte for byte as it was hashed.\n\nThis is a proof contract, not the archive's display contract: nothing here is formatted for rendering, so an entry changes only when the pick does. Unresolved ledger entries omit game identity and kickoff; sealed_at remains public commitment provenance. A commitment is never written after kickoff and never rewritten by an outcome correction; `resolved_at` moving under an unchanged `commitment_hash` is a corrected market re-mapping an already-settled pick.\n\nWithdrawal from current recommendations or the product archive does not remove a published ledger entry. The ledger retains every published commitment under its original identity and proof bytes; canonical market settlement still determines the recorded result.",
        "tags": ["Pick of the Day"],
        "security": [],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pick of the Day commitment ledger",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Stable validator for the current Pick of the Day ledger payload. Re-send it via If-None-Match for conditional GETs.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "pick_of_the_day_ledger"
                    },
                    "data": {
                      "$ref": "#/components/schemas/PickOfTheDayLedger"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "One entry in each state",
                    "value": {
                      "object": "pick_of_the_day_ledger",
                      "data": {
                        "entries": [
                          {
                            "state": "uncommitted",
                            "pick_date": "2026-06-22",
                            "pick_rank": 1,
                            "pre_commitment": true,
                            "outcome": "win",
                            "withdrawal_reason": null,
                            "matchup": "Spain vs. France",
                            "category": "Soccer",
                            "resolved_at": null,
                            "permalink": "https://0xinsider.com/pick-of-the-day/picks/1",
                            "payload": {
                              "backed_price": "0.6100",
                              "condition_id": "0xabc1230000000000000000000000000000000abc7f7f7f7f7f7f7f7f7f7f7f7f",
                              "kickoff": "2026-06-22T19:00:00Z",
                              "pick_date": "2026-06-22",
                              "pick_outcome_index": 0,
                              "pick_outcome_label": "Spain",
                              "pick_rank": 1,
                              "platform": "polymarket"
                            },
                            "pick_id": "1000",
                            "publication_order": 1,
                            "is_free_selection": true,
                            "supersedes_pick_id": null
                          },
                          {
                            "state": "opened",
                            "pick_date": "2026-09-20",
                            "pick_rank": 1,
                            "commitment_hash": "44d18fa5e2aa3a2bf3c971dcc9317c8ccbdfd5480a4773b6d8ffd5fbeeea84dc",
                            "commitment_nonce": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
                            "commitment_algo": "sha256(canonical_json(payload)||nonce)",
                            "sealed_at": "2026-09-20T17:00:04.318271Z",
                            "resolved_at": "2026-09-21T02:41:09.552310Z",
                            "kickoff": "2026-09-20T23:05:00Z",
                            "payload": {
                              "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"
                            },
                            "outcome": "win",
                            "withdrawal_reason": null,
                            "matchup": "Lakers vs. Warriors",
                            "category": "Basketball",
                            "permalink": "https://0xinsider.com/pick-of-the-day/picks/350",
                            "pick_id": "1001",
                            "publication_order": 1,
                            "is_free_selection": true,
                            "supersedes_pick_id": null,
                            "commitment_version": 1
                          }
                        ],
                        "entry_count": 2,
                        "sealed_count": 0,
                        "opened_count": 1,
                        "uncommitted_count": 1
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current Pick of the Day ledger payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged Pick of the Day ledger payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Integrity refusal: a ledger row failed a consistency check, for example a pending pick that arrived carrying a column that must stay withheld until it settles. The whole response is refused and the row logged, rather than publishing a partial or unsafe record; the body carries a generic message. A database connection failure answers 503 instead.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS 'https://api.0xinsider.com/api/v1/pick-of-the-day/ledger'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/leaderboard/trending": {
      "get": {
        "operationId": "listTrendingWallets",
        "summary": "List trending wallets",
        "description": "Returns wallets ranked by Polymarket weekly/monthly P&L (Polymarket-only discovery), with opaque page-cursor pagination. trending_pnl_usd and the by-PNL row order come from Polymarket's canonical leaderboard (data-api.polymarket.com/v2/leaderboard?time_period=week|month&sort_by=PNL), not a locally summed realized-leaf total. Each row also carries window volume, distinct markets, grade, hot-streak tier, and daily_pnl_series: the wallet's sports and esports realized P&L on each UTC day of the window, with daily_pnl_series_status ready or pending (pending: the series is empty and never means zero). It leaves out non-sports markets, so it does not sum to trending_pnl_usd. The response comes from a retained Redis board: meta.cached is true, and meta.cache_age_s reports the original board age when known (omitted when unknown). A backend read of a board at least 120 seconds old attempts a detached refresh; after a quiet spell a product board may be up to a day old. HTTP freshness ends at 120 seconds; max-age plus stale-while-revalidate cannot exceed the remaining original retention. Unknown age grants no cache window. A true cold read returns 503 (warming, retry-after), never a fabricated ranking. Polymarket-only: the read model filters platform = 'polymarket'. Cursors are bound to the effective limit, window and ranked-board generation; a changed board or request scope returns 400 with error.reason=cursor_expired, and legacy page-only cursors must restart from page one.",
        "tags": ["Leaderboard"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Polymarket's weekly leaderboard caps the ranked set at 50 wallets; requests above 50 still return at most 50. Out-of-range values are clamped to 1..50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor from a previous response, bound to its effective limit, window and ranked-board generation. A changed board or request scope returns error.reason=cursor_expired; legacy page-only cursors must restart from page one.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "window",
            "in": "query",
            "description": "Trailing window.",
            "schema": {
              "type": "string",
              "enum": ["7d", "30d"],
              "default": "7d"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Trending wallets list",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              },
              "Cache-Control": {
                "description": "Private age-aware freshness with at most 120 seconds from the original board computation. Any stale replay is capped by remaining original retention; unknown or expired backing grants max-age=0 and no stale replay. The same policy applies to 304.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TrendingWallet"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page; absent on the last page."
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total ranked rows when the read model exposes a count; may be absent."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [],
                      "has_more": false,
                      "meta": {
                        "request_id": "req_example",
                        "cached": true,
                        "cost": 1,
                        "cache_age_s": 180
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              },
              "Cache-Control": {
                "description": "Private age-aware freshness with at most 120 seconds from the original board computation. Any stale replay is capped by remaining original retention; unknown or expired backing grants max-age=0 and no stale replay. The same policy applies to 304.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. On this route a 503 has TWO distinct causes; branch on error.reason. (1) error.reason=\"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; consult that endpoint's contract and do not infer dependency health from this shared reason. This is endpoint-local unavailability, not rate limiting: retry only this route after Retry-After (or error.retry_at), and do not feed it into a rate-limit backoff shared with other endpoints. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the seconds until it probes Redis again. Both carry error.code=\"rate_limit_unavailable\" (a FROZEN contract value, so it cannot be split per cause) and X-Request-Id -- which is why error.reason, not error.code, is the discriminator.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until retrying is worth doing. With error.reason=\"read_model_warming\" this is the endpoint-local read-model retry interval; without a reason it is the rate-limiter outage cooldown. Always >= 1.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/leaderboard/trending?window=7d&limit=10'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/leaderboard/leagues": {
      "get": {
        "operationId": "listLeaderboardLeagues",
        "summary": "List the leagues that have a leaderboard",
        "description": "Every league with its own skill leaderboard, grouped by sport, most ranked wallets first. Each row's `sport` and `slug` are the `{sport}` path segment and `league` value of GET /api/v1/leaderboard/sports/{sport}. A league is listed once its edge sort ranks at least `min_ranked` wallets. 503 read_model_warming while the league ranking is missing or past its refresh window.",
        "tags": ["Leaderboard"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Leagues with a leaderboard",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Stable validator for the current league list. Re-send it via If-None-Match for conditional GETs.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "leaderboard_leagues"
                    },
                    "data": {
                      "$ref": "#/components/schemas/LeaderboardLeagues"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "leaderboard_leagues",
                      "data": {
                        "min_ranked": 20,
                        "min_resolved": 10,
                        "refreshed_at": "2026-11-01T12:00:00Z",
                        "leagues": [
                          {
                            "category": "Soccer",
                            "sport": "soccer",
                            "slug": "premier-league",
                            "name": "Premier League",
                            "ranked_traders": 412,
                            "total_traders": 1630
                          }
                        ]
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current Pick of the Day archive payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged Pick of the Day archive payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. On this route a 503 has TWO distinct causes; branch on error.reason. (1) error.reason=\"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; consult that endpoint's contract and do not infer dependency health from this shared reason. This is endpoint-local unavailability, not rate limiting: retry only this route after Retry-After (or error.retry_at), and do not feed it into a rate-limit backoff shared with other endpoints. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the seconds until it probes Redis again. Both carry error.code=\"rate_limit_unavailable\" (a FROZEN contract value, so it cannot be split per cause) and X-Request-Id -- which is why error.reason, not error.code, is the discriminator.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until retrying is worth doing. With error.reason=\"read_model_warming\" this is the endpoint-local read-model retry interval; without a reason it is the rate-limiter outage cooldown. Always >= 1.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/leaderboard/leagues'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/leaderboard/sports/{sport}": {
      "get": {
        "operationId": "getSportLeaderboard",
        "summary": "Get a sport or league leaderboard",
        "description": "One sport's skill leaderboard, or with `league` one league's, the board the site's sport pages show. Wallets need `min_resolved` resolved markets in the sport or league. `sort=edge` (the default) ranks `edge_skill`, the edge over the price paid pulled toward the board's `edge_average` by how much of the record is noise; a wallet without a ranked edge sorts after the ranked ones. `sort=pnl` ranks realized P&L, and `sort=win_rate` the Wilson lower bound of the win rate. Boards are ranked to 100 wallets; `limit` returns the head of that list. A sport slug outside sports and esports is 404 with error.param=sport; a league slug the sport has no board for is 404 with error.param=league (GET /api/v1/leaderboard/leagues lists them). 503 read_model_warming while the ranking is being rebuilt.",
        "tags": ["Leaderboard"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "sport",
            "in": "path",
            "required": true,
            "description": "The sport slug, for example soccer, basketball, football or esports. Matched case-insensitively. A league or title alias such as nba, epl or cs2 reads its sport's board, and the body's sport is that board's slug; pass league for one league's board.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "league",
            "in": "query",
            "required": false,
            "description": "A league slug of the sport, for example premier-league or cs2, from GET /api/v1/leaderboard/leagues. Omit it for the sport board.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Ranking axis. Any other value returns 400 bad_request with error.param=sort.",
            "schema": {
              "type": "string",
              "enum": ["edge", "pnl", "win_rate"],
              "default": "edge"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Rows to return from the top of the board. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sport or league leaderboard",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Stable validator for the current board. Re-send it via If-None-Match for conditional GETs.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "sport_leaderboard"
                    },
                    "data": {
                      "$ref": "#/components/schemas/SportLeaderboard"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "sport_leaderboard",
                      "data": {
                        "sport": "soccer",
                        "category": "Soccer",
                        "league": {
                          "slug": "premier-league",
                          "name": "Premier League",
                          "ranked_traders": 412
                        },
                        "sort": "edge",
                        "min_resolved": 10,
                        "limit": 1,
                        "total_traders": 1630,
                        "edge_average": 0.031,
                        "volume_scope": "sports_and_esports",
                        "as_of": "2026-11-01T12:00:00Z",
                        "rows": [
                          {
                            "rank": 1,
                            "id": "trd_0x1234567890abcdef1234567890abcdef12345678",
                            "address": "0x1234567890abcdef1234567890abcdef12345678",
                            "username": "example",
                            "platform": "polymarket",
                            "grade": "A",
                            "n_resolved": 84,
                            "wins": 52,
                            "losses": 32,
                            "win_rate": 0.619,
                            "win_rate_wilson_lb": 0.512,
                            "price_edge": {
                              "markets": 71,
                              "hit_rate": 0.62,
                              "avg_price": 0.51,
                              "edge": 0.11,
                              "edge_lower": 0.003,
                              "status": "ranked"
                            },
                            "edge_hold": null,
                            "edge_skill": 0.082,
                            "pnl": 18250.4,
                            "volume": 412000.0,
                            "cost": 96500.0,
                            "roi": 0.189,
                            "last_category_trade_at": "2026-10-31T19:45:00Z"
                          }
                        ]
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current Pick of the Day archive payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged Pick of the Day archive payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "The sport slug is outside sports and esports (error.param=sport), or the sport has no board for that league slug (error.param=league).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. On this route a 503 has TWO distinct causes; branch on error.reason. (1) error.reason=\"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; consult that endpoint's contract and do not infer dependency health from this shared reason. This is endpoint-local unavailability, not rate limiting: retry only this route after Retry-After (or error.retry_at), and do not feed it into a rate-limit backoff shared with other endpoints. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the seconds until it probes Redis again. Both carry error.code=\"rate_limit_unavailable\" (a FROZEN contract value, so it cannot be split per cause) and X-Request-Id -- which is why error.reason, not error.code, is the discriminator.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until retrying is worth doing. With error.reason=\"read_model_warming\" this is the endpoint-local read-model retry interval; without a reason it is the rate-limiter outage cooldown. Always >= 1.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/leaderboard/sports/soccer?league=premier-league&sort=pnl'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/leaderboard/categories": {
      "get": {
        "operationId": "listCategoryLeaders",
        "summary": "List every category's top edge leaders",
        "description": "Every sports and esports category's top three edge leaders in one read, the board the site's categories index shows. In each category, wallets are ranked as GET /api/v1/leaderboard/categories/{slug} ranks them, by the 95% lower bound of their edge over the price they paid; only wallets whose lower bound is above zero are listed, so a category can carry fewer than three, or none. Rows come by category, then rank, in the same row shape as the per-category board. Not paginated. 503 read_model_warming, with Retry-After, while the category-skill ranking is being rebuilt or its model is degraded: never an empty 200.",
        "tags": ["Leaderboard"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Top three edge leaders of every sports and esports category",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Stable validator for the current categories index. Re-send it via If-None-Match for conditional GETs.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CategoryLeader"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer",
                      "description": "Number of rows returned: up to three per category."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "value": {
                      "object": "list",
                      "data": [
                        {
                          "rank": 1,
                          "category": "Soccer",
                          "id": "trd_0x1234567890abcdef1234567890abcdef12345678",
                          "address": "0x1234567890abcdef1234567890abcdef12345678",
                          "username": "example",
                          "platform": "polymarket",
                          "grade": "A",
                          "edge_lower_bound": 0.184,
                          "independent_events": 31,
                          "unresolved_events": 0,
                          "n_resolved": 479,
                          "win_rate": 0.7286,
                          "pnl": 18076.35,
                          "as_of": "2026-11-01T22:59:07.413338Z"
                        },
                        {
                          "rank": 1,
                          "category": "Tennis",
                          "id": "trd_0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
                          "address": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
                          "username": null,
                          "platform": "polymarket",
                          "grade": "S",
                          "edge_lower_bound": 0.1412,
                          "independent_events": 58,
                          "unresolved_events": 2,
                          "n_resolved": 611,
                          "win_rate": 0.6907,
                          "pnl": 9420.1,
                          "as_of": "2026-11-01T22:59:07.413338Z"
                        }
                      ],
                      "has_more": false,
                      "total": 2,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current categories index payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged leaderboard payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Bad request. With X-Query-Validation: strict, an unknown query name returns error.reason=unknown_query_parameter; this route takes no query parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. On this route a 503 has TWO distinct causes; branch on error.reason. (1) error.reason=\"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; consult that endpoint's contract and do not infer dependency health from this shared reason. This is endpoint-local unavailability, not rate limiting: retry only this route after Retry-After (or error.retry_at), and do not feed it into a rate-limit backoff shared with other endpoints. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the seconds until it probes Redis again. Both carry error.code=\"rate_limit_unavailable\" (a FROZEN contract value, so it cannot be split per cause) and X-Request-Id -- which is why error.reason, not error.code, is the discriminator.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until retrying is worth doing. With error.reason=\"read_model_warming\" this is the endpoint-local read-model retry interval; without a reason it is the rate-limiter outage cooldown. Always >= 1.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/leaderboard/categories'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/leaderboard/categories/{slug}": {
      "get": {
        "operationId": "getCategoryLeaderboard",
        "summary": "Get a category's edge leaderboard",
        "description": "One sports or esports category's edge leaderboard, the board the site's category pages show. Wallets are ranked by edge_lower_bound, the 95% lower bound of their edge over the price they paid in the category, counted over independent events (independent_events breaks ties, then the wallet). Only wallets whose lower bound is above zero are listed; total counts them across every page. active_within keeps wallets that traded in the category within 7d, 30d or 90d, and min_events sets the independent events a wallet needs. A sibling of GET /api/v1/leaderboard and GET /api/v1/leaderboard/sports/{sport}, which rank the grade score and the settled-record edge; this ranking is the category-skill model's lower bound, with its own cursor. A slug outside sports and esports is 404 with error.param=slug. 503 read_model_warming, with Retry-After, while the category-skill ranking is being rebuilt or its model is degraded: never an empty 200.",
        "tags": ["Leaderboard"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "The category slug, for example soccer, basketball, tennis or esports, as GET /api/v1/leaderboard/categories lists it lowercased. Matched case-insensitively.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "active_within",
            "in": "query",
            "description": "Keep wallets that traded in the category within this window. all (the default) keeps every ranked wallet.",
            "schema": {
              "type": "string",
              "enum": ["all", "7d", "30d", "90d"],
              "default": "all"
            }
          },
          {
            "name": "min_events",
            "in": "query",
            "description": "Independent events a wallet needs in the category to be listed. The site offers 0, 50, 100 and 250. Clamped to 0..1000000.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of leaders to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque cel_ pagination cursor from a prior response. It binds the lower-bound/independent-event/wallet boundary to the committed category-skill ranking and to the slug, active_within and min_events of the request that issued it; a cursor from another filter is 400 on cursor, and one issued before the ranking refreshed is 400 with error.reason=cursor_expired.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One category's edge leaders, best lower bound first",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Stable validator for the current page. Re-send it via If-None-Match for conditional GETs.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CategoryLeader"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer",
                      "description": "Wallets in the category whose edge lower bound is above zero, Wallets in the full walk across every page: those in the category, under this request's active_within and min_events, whose edge lower bound is above zero. The same on every page."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "value": {
                      "object": "list",
                      "data": [
                        {
                          "rank": 1,
                          "category": "Soccer",
                          "id": "trd_0x1234567890abcdef1234567890abcdef12345678",
                          "address": "0x1234567890abcdef1234567890abcdef12345678",
                          "username": "example",
                          "platform": "polymarket",
                          "grade": "A",
                          "edge_lower_bound": 0.184,
                          "independent_events": 31,
                          "unresolved_events": 0,
                          "n_resolved": 479,
                          "win_rate": 0.7286,
                          "pnl": 18076.35,
                          "as_of": "2026-11-01T22:59:07.413338Z"
                        },
                        {
                          "rank": 2,
                          "category": "Soccer",
                          "id": "trd_0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
                          "address": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
                          "username": null,
                          "platform": "polymarket",
                          "grade": "S",
                          "edge_lower_bound": 0.1223,
                          "independent_events": 66,
                          "unresolved_events": 0,
                          "n_resolved": 829,
                          "win_rate": 0.7503,
                          "pnl": 31907.45,
                          "as_of": "2026-11-01T22:59:07.413338Z"
                        }
                      ],
                      "has_more": true,
                      "next_cursor": "cel_example",
                      "total": 412,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current page of the category's ranking.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged leaderboard payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Bad request: active_within outside all, 7d, 30d, 90d (error.param=active_within), or a malformed cursor or one from another filter (error.param=cursor). error.reason=cursor_expired with error.param=cursor means the category-skill ranking refreshed since the cursor was issued: discard accumulated rows, request the first page again, and continue with its next_cursor. There is no retry delay.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "The slug is not a sports or esports category (error.param=slug). GET /api/v1/leaderboard/categories lists the categories with leaders.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. On this route a 503 has TWO distinct causes; branch on error.reason. (1) error.reason=\"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; consult that endpoint's contract and do not infer dependency health from this shared reason. This is endpoint-local unavailability, not rate limiting: retry only this route after Retry-After (or error.retry_at), and do not feed it into a rate-limit backoff shared with other endpoints. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the seconds until it probes Redis again. Both carry error.code=\"rate_limit_unavailable\" (a FROZEN contract value, so it cannot be split per cause) and X-Request-Id -- which is why error.reason, not error.code, is the discriminator.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until retrying is worth doing. With error.reason=\"read_model_warming\" this is the endpoint-local read-model retry interval; without a reason it is the rate-limiter outage cooldown. Always >= 1.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/leaderboard/categories/soccer?limit=20'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/markets/search": {
      "get": {
        "operationId": "searchMarkets",
        "summary": "Search markets",
        "description": "Search prediction markets by keyword. Returns one representative market per matching event, preferring the market whose title is q, then a winner market over a spread, total or prop, with status, category, platform metadata and the event_slug. Cursor pagination advances over grouped market results rather than raw sub-market rows. To list every market of a game, pass the event_slug to GET /api/v1/games/{event_slug}/markets. Returns sports and esports markets only (#27411). Searches every unresolved game market (a game's winner market, or an outright) whether or not it has traded, and every market that has had a single trade of $10,000 or more, resolved or not; a resolved market that never had such a trade is not returned (#32215). Events rank by title similarity to q, a nearer game date first among similar matches; an event holding a market whose title is q (case-insensitive, with or without its closing question mark) ranks first whatever its date, so pasting a market's title returns that market first (#32280).",
        "tags": ["Markets"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Search query. Must be 2-512 characters before whitespace trimming and hold at least 2 letters or digits after trimming; a query with fewer letters or digits (a, 7, ?) returns 400 bad_request with param q (#32309).",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 512
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of matching markets to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Pagination cursor from previous response's next_cursor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by market status. A market is closed once Polymarket has closed trading or it has resolved, and active otherwise; all returns both.",
            "schema": {
              "type": "string",
              "enum": ["active", "closed", "all"],
              "default": "all"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "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).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Search results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MarketSearchResult"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total matching rows when the read model exposes a count; the key is absent when it does not."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [],
                      "has_more": false,
                      "total": 0,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/markets/search?q=lakers&status=active'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/content/search": {
      "get": {
        "operationId": "searchContent",
        "summary": "Search editorial content",
        "description": "Search 0xinsider editorial content by keyword. Returns backend-owned learn, glossary, comparison, research, and trading-strategy items with canonical URLs. Opaque ranking scores are not exposed.",
        "tags": ["Content"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Search query. Must be 1-256 characters before whitespace trimming and non-empty after trimming.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 256
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum content items to return. Out-of-range values are clamped to 1..50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Editorial content search results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ContentSearchResult"
                      }
                    },
                    "has_more": {
                      "type": "boolean",
                      "const": false
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Omitted because content search is a bounded one-page result."
                    },
                    "total": {
                      "type": "integer",
                      "description": "Absent because content search is a bounded relevance result and does not run a count query."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [],
                      "has_more": false,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/content/search?q=polymarket%20fees'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/markets/explore": {
      "get": {
        "operationId": "exploreMarkets",
        "summary": "Explore markets",
        "description": "Browse whale-active titled markets with category, platform, status, and keyword filters. Explore is Polymarket-only: the platform parameter is accepted for backward-compatibility but every request returns Polymarket markets. Paginates visible discovery entries rather than raw market rows, returns live category/platform facets alongside grouped event clusters or standalone markets, and includes total on the first page only. Each grouped event contains at most 12 markets, retaining the selected representative within that cap. Categories come straight from provider metadata (Polymarket Gamma) and facets are flat value/label/count rows. Returns sports and esports markets only (#27411).",
        "tags": ["Markets"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "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.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by market status. A market is closed once Polymarket has closed trading or it has resolved, and active otherwise; all returns both.",
            "schema": {
              "type": "string",
              "enum": ["active", "closed", "all"],
              "default": "all"
            }
          },
          {
            "name": "platform",
            "in": "query",
            "description": "Filter by source platform. Explore is Polymarket-only; polymarket is the only supported value and the parameter is accepted for backward-compatibility but does not change the result set.",
            "schema": {
              "type": "string",
              "enum": ["polymarket"],
              "default": "polymarket"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort order for the discovery feed. `large_trades` ranks by large-trade activity; `whales` is its deprecated spelling and selects the same order until its sunset on 2027-02-01 (#29352); from then it answers 400 bad_request.",
            "schema": {
              "type": "string",
              "enum": ["trending", "hot", "expiring", "large_trades", "whales", "volume", "newest"],
              "default": "trending"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor from the previous response.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size. Out-of-range values are clamped to 1..48.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 48,
              "default": 24
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Keyword search against market titles. At most 64 characters before whitespace trimming.",
            "schema": {
              "type": "string",
              "maxLength": 64
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Grouped market discovery results",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Stable validator for the current explore payload. Re-send it via If-None-Match for conditional GETs.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "facets", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ExploreEntry"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total matching visible entries after grouping. Present on the first page and omitted on cursor pages."
                    },
                    "facets": {
                      "$ref": "#/components/schemas/ExploreFacets"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    },
                    "computed_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When this response body was computed. Present whenever the body came from, or was just written to, the 60s explore cache. Pair it with fresh_for_seconds to derive how much longer the body may be reused: fresh_for_seconds - age(computed_at). Excluded from the ETag validator, so a body recomputed with identical data keeps its validator."
                    },
                    "fresh_for_seconds": {
                      "type": "integer",
                      "description": "How long the body computed at computed_at is good for, in seconds. Deliberately not pre-subtracted: a cached body cannot carry a number that changes while it sits in the cache. Excluded from the ETag validator."
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [
                        {
                          "type": "group",
                          "event_slug": "nfl-nyg-la-2026-09-22",
                          "parent_title": "Giants vs. Rams",
                          "image": "https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl.png",
                          "platform": "polymarket",
                          "category": "NFL",
                          "markets": [
                            {
                              "id": "mkt_0xabc1230000000000000000000000000000000abc613f54180a6d82f81c586f87",
                              "condition_id": "0xabc1230000000000000000000000000000000abc613f54180a6d82f81c586f87",
                              "title": "Giants vs. Rams",
                              "slug": "nfl-nyg-la-2026-09-22",
                              "url_slug": "nfl-nyg-la-2026-09-22",
                              "image": "https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl.png",
                              "icon": "https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl.png",
                              "category": "NFL",
                              "platform": "polymarket",
                              "status": "active",
                              "volume": 7381997.07,
                              "liquidity": 828265.76,
                              "whale_trade_count": 18,
                              "large_trade_count": 18,
                              "whale_distinct_wallets": 12,
                              "large_trade_distinct_wallets": 12,
                              "whale_total_usd": 623663.53,
                              "large_trade_total_usd": 623663.53,
                              "whale_last_trade_at": "2026-09-22T02:05:52Z",
                              "large_trade_last_at": "2026-09-22T02:05:52Z",
                              "end_date": "2026-09-22T00:15:00Z",
                              "created_at": "2026-08-11T12:00:11.489584Z",
                              "outcome_yes": "Giants",
                              "outcome_no": "Rams",
                              "token_id_yes": "4661468695364133352504208359262294490681982643646457249320367691664724099857",
                              "token_id_no": "43677542496120548237382622015301078356830156697348317225498679221043021866409",
                              "event_slug": "nfl-nyg-la-2026-09-22",
                              "smart_score": -0.9999414953194173,
                              "smart_count": 14,
                              "smart_label": "Rams",
                              "sharp_money_as_of": "2026-09-19T16:42:07Z",
                              "outcome_yes_label": "Giants",
                              "outcome_no_label": "Rams",
                              "outcome_yes_provider_id": null,
                              "outcome_no_provider_id": null,
                              "open_interest": 4827946.902008,
                              "oi_change_pct": 818.6106074586263,
                              "price_points": [
                                [1789963213, 0.265],
                                [1789966815, 0.265],
                                [1789970413, 0.265]
                              ],
                              "no_price_points": [
                                [1789963211, 0.735],
                                [1789966814, 0.735],
                                [1789970412, 0.735]
                              ],
                              "last_price": 0.0005,
                              "no_last_price": 0.9995,
                              "change_pct_24h": -99.81132075471699,
                              "no_change_pct_24h": 35.98639455782314,
                              "discover_score": 757.91,
                              "score_components": {
                                "volume_signal": 284.66,
                                "whale_signal": 344.24,
                                "large_trade_signal": 344.24,
                                "liquidity_signal": 109.01,
                                "recency_signal": 20,
                                "sharp_money_signal": 0,
                                "smart_money_signal": 0,
                                "price_move_signal": 99.81,
                                "missing_price_penalty": 0
                              },
                              "freshness": {
                                "enrichment_status": "available",
                                "price_status": "available"
                              }
                            },
                            {
                              "id": "mkt_0xdef4560000000000000000000000000000000def5d625ced3aab59ab944b0149",
                              "condition_id": "0xdef4560000000000000000000000000000000def5d625ced3aab59ab944b0149",
                              "title": "Spread: Rams (-6.5)",
                              "slug": "nfl-nyg-la-2026-09-22-spread-home-6pt5",
                              "url_slug": "nfl-nyg-la-2026-09-22-spread-home-6pt5",
                              "image": "https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl.png",
                              "icon": "https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl.png",
                              "category": "NFL",
                              "platform": "polymarket",
                              "status": "active",
                              "volume": 1771718.51,
                              "liquidity": 248860.04,
                              "whale_trade_count": 1,
                              "large_trade_count": 1,
                              "whale_distinct_wallets": 1,
                              "large_trade_distinct_wallets": 1,
                              "whale_total_usd": 31200,
                              "large_trade_total_usd": 31200,
                              "whale_last_trade_at": "2026-09-21T18:28:47Z",
                              "large_trade_last_at": "2026-09-21T18:28:47Z",
                              "end_date": "2026-09-22T00:15:00Z",
                              "created_at": null,
                              "outcome_yes": "Rams",
                              "outcome_no": "Giants",
                              "token_id_yes": "70559970467755656860388256309445764511942874931136416008858426344324056285882",
                              "token_id_no": "101693339364586689364540822236169180116014062262373180943098113798769516613300",
                              "event_slug": "nfl-nyg-la-2026-09-22",
                              "smart_score": null,
                              "smart_count": null,
                              "smart_label": null,
                              "sharp_money_as_of": null,
                              "outcome_yes_label": "Rams",
                              "outcome_no_label": "Giants",
                              "outcome_yes_provider_id": null,
                              "outcome_no_provider_id": null,
                              "open_interest": null,
                              "oi_change_pct": null,
                              "price_points": [
                                [1789963212, 0.525],
                                [1789966814, 0.525],
                                [1789970412, 0.525]
                              ],
                              "no_price_points": [
                                [1789963212, 0.475],
                                [1789966814, 0.475],
                                [1789970412, 0.475]
                              ],
                              "last_price": 0.9995,
                              "no_last_price": 0.0005,
                              "change_pct_24h": 90.38095238095238,
                              "no_change_pct_24h": -99.89473684210526,
                              "discover_score": 628.72,
                              "score_components": {
                                "volume_signal": 258.97,
                                "whale_signal": 250.35,
                                "large_trade_signal": 250.35,
                                "liquidity_signal": 99.39,
                                "recency_signal": 20,
                                "sharp_money_signal": null,
                                "smart_money_signal": null,
                                "price_move_signal": 90.38,
                                "missing_price_penalty": 0
                              },
                              "freshness": {
                                "enrichment_status": "unavailable",
                                "price_status": "available"
                              }
                            }
                          ],
                          "rep_volume": 7381997.07,
                          "rep_whales": 12,
                          "rep_large_trades": 12
                        },
                        {
                          "type": "standalone",
                          "market": {
                            "id": "mkt_0xdef4560000000000000000000000000000000def4c2638b15eda50ca1b7ce303",
                            "condition_id": "0xdef4560000000000000000000000000000000def4c2638b15eda50ca1b7ce303",
                            "title": "Dallas Wings vs. Phoenix Mercury",
                            "slug": "wnba-dal-phx-2026-09-21",
                            "url_slug": "wnba-dal-phx-2026-09-21",
                            "image": "https://polymarket-upload.s3.us-east-2.amazonaws.com/wnba-logo-PAR4befDAubM.png",
                            "icon": "https://polymarket-upload.s3.us-east-2.amazonaws.com/wnba-logo-PAR4befDAubM.png",
                            "category": "WNBA",
                            "platform": "polymarket",
                            "status": "active",
                            "volume": 214180.96,
                            "liquidity": 180183.25,
                            "whale_trade_count": 1,
                            "large_trade_count": 1,
                            "whale_distinct_wallets": 1,
                            "large_trade_distinct_wallets": 1,
                            "whale_total_usd": 16292.73,
                            "large_trade_total_usd": 16292.73,
                            "whale_last_trade_at": "2026-09-22T02:04:20Z",
                            "large_trade_last_at": "2026-09-22T02:04:20Z",
                            "end_date": "2026-09-22T02:00:00Z",
                            "created_at": "2026-09-08T05:48:06.531425Z",
                            "outcome_yes": "Dallas Wings",
                            "outcome_no": "Phoenix Mercury",
                            "token_id_yes": "26603239767113701790776634803790654539492519362779665632490658212718064984767",
                            "token_id_no": "63625967510349184920927952425890439521145813842589613381435268277105144709593",
                            "event_slug": "wnba-dal-phx-2026-09-21",
                            "smart_score": null,
                            "smart_count": null,
                            "smart_label": null,
                            "sharp_money_as_of": null,
                            "outcome_yes_label": "Dallas Wings",
                            "outcome_no_label": "Phoenix Mercury",
                            "outcome_yes_provider_id": null,
                            "outcome_no_provider_id": null,
                            "open_interest": null,
                            "oi_change_pct": null,
                            "price_points": [
                              [1789963210, 0.695],
                              [1789966812, 0.695],
                              [1789970410, 0.685]
                            ],
                            "no_price_points": [
                              [1789963211, 0.305],
                              [1789966813, 0.305],
                              [1789970411, 0.315]
                            ],
                            "last_price": 0.755,
                            "no_last_price": 0.245,
                            "change_pct_24h": 8.633093525179865,
                            "no_change_pct_24h": -19.672131147540984,
                            "discover_score": 572.52,
                            "score_components": {
                              "volume_signal": 220.94,
                              "whale_signal": 234.76,
                              "large_trade_signal": 234.76,
                              "liquidity_signal": 96.81,
                              "recency_signal": 20,
                              "sharp_money_signal": null,
                              "smart_money_signal": null,
                              "price_move_signal": 8.63,
                              "missing_price_penalty": 0
                            },
                            "freshness": {
                              "enrichment_status": "unavailable",
                              "price_status": "available"
                            }
                          }
                        }
                      ],
                      "has_more": true,
                      "next_cursor": "ZXhfMjAyNi0wOS0yMlQwMjowNDoyMCswMDowMHwweDMyZWMxMGM0NjAyZjc1M2M1NmQwMGJiZjkyZjRkYzIxMmE1YmUwYTM0YzI2MzhiMTVlZGE1MGNhMWI3Y2UzMDM",
                      "total": 371,
                      "facets": {
                        "categories": [
                          {
                            "value": "Soccer",
                            "label": "Soccer",
                            "count": 89
                          },
                          {
                            "value": "Tennis",
                            "label": "Tennis",
                            "count": 74
                          },
                          {
                            "value": "Baseball",
                            "label": "Baseball",
                            "count": 73
                          }
                        ],
                        "platforms": [
                          {
                            "value": "polymarket",
                            "label": "Polymarket",
                            "count": 371
                          }
                        ]
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      },
                      "computed_at": "2026-09-22T03:08:59.496925Z",
                      "fresh_for_seconds": 60
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current explore payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged explore payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/markets/explore'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/markets/smart-money-flows": {
      "get": {
        "operationId": "listSmartMoneyFlows",
        "summary": "List ranked sharp-money flows (deprecated alias)",
        "description": "Ranks sports and esports markets (#27306) by absolute net S/A/B-grade whale flow over a requested timeframe. Use this discovery endpoint to answer where sharp money is flowing before drilling into a specific market with /api/v1/market/{condition_id}/flow. Pagination is anchored by an opaque cursor carrying the first-page as_of timestamp, normalized effective filters, ranking revision and aggregate collection revision; a changed filter or collection returns `cursor_expired` so callers request the first page again. Deprecated alias of GET /api/v1/markets/sharp-money-flows, kept live until its sunset on 2027-02-01 (#29351); every response carries `Deprecation: @1783276950` (RFC 9745, 2026-07-05T18:42:30Z) and a `Link` to the successor (`rel=\"successor-version\"`) and to the versioning policy (`rel=\"deprecation\"`). `Sunset: Mon, 01 Feb 2027 00:00:00 GMT` (RFC 8594) names that date, after which the path answers 410 Gone with error.code endpoint_retired.",
        "tags": ["Markets"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "timeframe",
            "in": "query",
            "description": "Lookback window for grade-filtered whale flow aggregation.",
            "schema": {
              "type": "string",
              "enum": ["1h", "4h", "24h", "7d"],
              "default": "24h"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "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.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "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).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "platform",
            "in": "query",
            "description": "Filter by source platform. all is a request-side no-op.",
            "schema": {
              "type": "string",
              "enum": ["polymarket", "all"],
              "default": "all"
            }
          },
          {
            "name": "min_grade",
            "in": "query",
            "description": "Minimum latest trader grade included in the flow. Default B means S/A/B only; unranked traders are excluded.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"],
              "default": "B"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "description": "Optional post-aggregate flow direction filter.",
            "schema": {
              "type": "string",
              "enum": ["YES", "NO"]
            }
          },
          {
            "name": "condition_id",
            "in": "query",
            "description": "Only this market's flow: an exact raw provider condition_id. Cannot be combined with event_slug (400). An unknown market returns an empty list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "event_slug",
            "in": "query",
            "description": "Only the markets of one game: every market of the game behind this event slug, the moneyline, spreads, totals and props, as GET /api/v1/games/{event_slug}/trades reads them, ranked as the unfiltered list ranks. Matched case-insensitively; cannot be combined with condition_id (400). An unknown slug answers 404 not_found with error.param event_slug.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ranked market sharp-money flows",
            "headers": {
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Deprecation": {
                "description": "RFC 9745 structured-field date when this alias was deprecated (2026-07-05T18:42:30Z).",
                "schema": {
                  "type": "string",
                  "example": "@1783276950"
                }
              },
              "Link": {
                "description": "RFC 8288 links to the successor operation (rel=\"successor-version\") and the deprecation policy (rel=\"deprecation\").",
                "schema": {
                  "type": "string"
                }
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SmartMoneyFlowMarket"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [
                        {
                          "market": {
                            "id": "mkt_0x123",
                            "condition_id": "0x123",
                            "title": "Giants vs. Rams",
                            "slug": "nfl-nyg-la-2026-09-22",
                            "category": "NFL",
                            "platform": "polymarket"
                          },
                          "sharp_money": {
                            "net_flow_usd": 12345.67,
                            "direction": "YES",
                            "token_id": "26603239767113701790776634803790654539492519362779665632490658212718064984767",
                            "large_trade_count": 7,
                            "whale_trade_count": 7,
                            "buy_volume_usd": 20000,
                            "sell_volume_usd": 7654.33
                          },
                          "smart_money": {
                            "net_flow_usd": 12345.67,
                            "direction": "YES",
                            "token_id": "26603239767113701790776634803790654539492519362779665632490658212718064984767",
                            "large_trade_count": 7,
                            "whale_trade_count": 7,
                            "buy_volume_usd": 20000,
                            "sell_volume_usd": 7654.33
                          },
                          "timeframe": "24h"
                        }
                      ],
                      "has_more": false,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 3
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Bad request. On this cursor-paginated route a 400 has TWO distinct causes; branch on error.reason. (1) error.reason=\"cursor_expired\" (with error.param=\"cursor\"): the pagination cursor was invalidated by an upstream data change mid-walk (e.g. the ranking snapshot behind the page refreshed). It is NOT a malformed parameter and NOT a reason to stop: recovery is mechanical -- re-request the first page and walk forward again. There is deliberately no Retry-After and no error.retry_at, because waiting changes nothing. (2) no error.reason: an ordinary invalid request parameter -- check error.param when present, otherwise error.message. Both carry error.code=\"bad_request\" (a FROZEN contract value), so error.reason is the discriminator.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/markets/smart-money-flows?timeframe=7d&min_grade=B&limit=10'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 3
            }
          }
        },
        "deprecated": true,
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/markets/sharp-money-flows": {
      "get": {
        "operationId": "listSharpMoneyFlows",
        "summary": "List ranked sharp-money flows",
        "description": "Canonical path for ranked sharp-money flows; /api/v1/markets/smart-money-flows remains live as a deprecated byte-identical alias of it. Ranks sports and esports markets (#27306) by absolute net S/A/B-grade whale flow over a requested timeframe. Use this discovery endpoint to answer where sharp money is flowing before drilling into a specific market with /api/v1/market/{condition_id}/flow. Pagination is anchored by an opaque cursor carrying the first-page as_of timestamp, normalized effective filters, ranking revision and aggregate collection revision; a changed filter or collection returns `cursor_expired` so callers request the first page again.",
        "tags": ["Markets"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "timeframe",
            "in": "query",
            "description": "Lookback window for grade-filtered whale flow aggregation.",
            "schema": {
              "type": "string",
              "enum": ["1h", "4h", "24h", "7d"],
              "default": "24h"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "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.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "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).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "platform",
            "in": "query",
            "description": "Filter by source platform. all is a request-side no-op.",
            "schema": {
              "type": "string",
              "enum": ["polymarket", "all"],
              "default": "all"
            }
          },
          {
            "name": "min_grade",
            "in": "query",
            "description": "Minimum latest trader grade included in the flow. Default B means S/A/B only; unranked traders are excluded.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"],
              "default": "B"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "description": "Optional post-aggregate flow direction filter.",
            "schema": {
              "type": "string",
              "enum": ["YES", "NO"]
            }
          },
          {
            "name": "condition_id",
            "in": "query",
            "description": "Only this market's flow: an exact raw provider condition_id. Cannot be combined with event_slug (400). An unknown market returns an empty list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "event_slug",
            "in": "query",
            "description": "Only the markets of one game: every market of the game behind this event slug, the moneyline, spreads, totals and props, as GET /api/v1/games/{event_slug}/trades reads them, ranked as the unfiltered list ranks. Matched case-insensitively; cannot be combined with condition_id (400). An unknown slug answers 404 not_found with error.param event_slug.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ranked market sharp-money flows",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SmartMoneyFlowMarket"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [
                        {
                          "market": {
                            "id": "mkt_0x123",
                            "condition_id": "0x123",
                            "title": "Giants vs. Rams",
                            "slug": "nfl-nyg-la-2026-09-22",
                            "category": "NFL",
                            "platform": "polymarket"
                          },
                          "sharp_money": {
                            "net_flow_usd": 12345.67,
                            "direction": "YES",
                            "token_id": "26603239767113701790776634803790654539492519362779665632490658212718064984767",
                            "large_trade_count": 7,
                            "whale_trade_count": 7,
                            "buy_volume_usd": 20000,
                            "sell_volume_usd": 7654.33
                          },
                          "smart_money": {
                            "net_flow_usd": 12345.67,
                            "direction": "YES",
                            "token_id": "26603239767113701790776634803790654539492519362779665632490658212718064984767",
                            "large_trade_count": 7,
                            "whale_trade_count": 7,
                            "buy_volume_usd": 20000,
                            "sell_volume_usd": 7654.33
                          },
                          "timeframe": "24h"
                        }
                      ],
                      "has_more": false,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 3
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Bad request. On this cursor-paginated route a 400 has TWO distinct causes; branch on error.reason. (1) error.reason=\"cursor_expired\" (with error.param=\"cursor\"): the pagination cursor was invalidated by an upstream data change mid-walk (e.g. the ranking snapshot behind the page refreshed). It is NOT a malformed parameter and NOT a reason to stop: recovery is mechanical -- re-request the first page and walk forward again. There is deliberately no Retry-After and no error.retry_at, because waiting changes nothing. (2) no error.reason: an ordinary invalid request parameter -- check error.param when present, otherwise error.message. Both carry error.code=\"bad_request\" (a FROZEN contract value), so error.reason is the discriminator.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/markets/sharp-money-flows?timeframe=7d&min_grade=B&limit=10'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 3
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/sports/pre-game-sides": {
      "get": {
        "tags": ["Markets"],
        "operationId": "listPreGameSides",
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "summary": "Retired sports edge endpoint",
        "description": "Retired permanently. Authenticated requests return 410 endpoint_retired and no sports data. Use GET /api/v1/edge-hunter?view=signals with Max to retain the full records and advanced query capabilities. Restart pagination at page one; retired route cursors cannot be reused.",
        "deprecated": true,
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["read"]
          }
        ],
        "parameters": [],
        "responses": {
          "400": {
            "description": "Bad request. On this cursor-paginated route a 400 has TWO distinct causes; branch on error.reason. (1) error.reason=\"cursor_expired\" (with error.param=\"cursor\"): the pagination cursor was invalidated by an upstream data change mid-walk (e.g. the ranking snapshot behind the page refreshed). It is NOT a malformed parameter and NOT a reason to stop: recovery is mechanical -- re-request the first page and walk forward again. There is deliberately no Retry-After and no error.retry_at, because waiting changes nothing. (2) no error.reason: an ordinary invalid request parameter -- check error.param when present, otherwise error.message. Both carry error.code=\"bad_request\" (a FROZEN contract value), so error.reason is the discriminator.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden: the credential cannot access this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "410": {
            "description": "This endpoint is retired. error.code and error.reason are endpoint_retired; error.doc_url names Edge Hunter. Stop calling this path and migrate to GET /api/v1/edge-hunter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/sports/pre-game-side-observations": {
      "get": {
        "tags": ["Markets"],
        "operationId": "listPreGameSideObservations",
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "summary": "Retired sports edge endpoint",
        "description": "Retired permanently. Authenticated requests return 410 endpoint_retired and no sports data. Use GET /api/v1/edge-hunter?view=observations with Max to retain the full records and advanced query capabilities. Restart pagination at page one; retired route cursors cannot be reused.",
        "deprecated": true,
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["read"]
          }
        ],
        "parameters": [],
        "responses": {
          "400": {
            "description": "Bad request. On this cursor-paginated route a 400 has TWO distinct causes; branch on error.reason. (1) error.reason=\"cursor_expired\" (with error.param=\"cursor\"): the pagination cursor was invalidated by an upstream data change mid-walk (e.g. the ranking snapshot behind the page refreshed). It is NOT a malformed parameter and NOT a reason to stop: recovery is mechanical -- re-request the first page and walk forward again. There is deliberately no Retry-After and no error.retry_at, because waiting changes nothing. (2) no error.reason: an ordinary invalid request parameter -- check error.param when present, otherwise error.message. Both carry error.code=\"bad_request\" (a FROZEN contract value), so error.reason is the discriminator.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden: the credential cannot access this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. On this route a 503 has TWO distinct causes; branch on error.reason. (1) error.reason=\"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; consult that endpoint's contract and do not infer dependency health from this shared reason. This is endpoint-local unavailability, not rate limiting: retry only this route after Retry-After (or error.retry_at), and do not feed it into a rate-limit backoff shared with other endpoints. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the seconds until it probes Redis again. Both carry error.code=\"rate_limit_unavailable\" (a FROZEN contract value, so it cannot be split per cause) and X-Request-Id -- which is why error.reason, not error.code, is the discriminator.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until retrying is worth doing. With error.reason=\"read_model_warming\" this is the endpoint-local read-model retry interval; without a reason it is the rate-limiter outage cooldown. Always >= 1.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "410": {
            "description": "This endpoint is retired. error.code and error.reason are endpoint_retired; error.doc_url names Edge Hunter. Stop calling this path and migrate to GET /api/v1/edge-hunter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/sports-edge-signals": {
      "get": {
        "tags": ["Markets"],
        "operationId": "listSportsEdgeSignals",
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "summary": "Retired sports edge endpoint",
        "description": "Retired permanently. Authenticated requests return 410 endpoint_retired and no sports data. Use GET /api/v1/edge-hunter?view=signals with Max to retain the full records and advanced query capabilities. Restart pagination at page one; retired route cursors cannot be reused.",
        "deprecated": true,
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["read"]
          }
        ],
        "parameters": [],
        "responses": {
          "400": {
            "description": "Bad request. On this cursor-paginated route a 400 has TWO distinct causes; branch on error.reason. (1) error.reason=\"cursor_expired\" (with error.param=\"cursor\"): the pagination cursor was invalidated by an upstream data change mid-walk (e.g. the ranking snapshot behind the page refreshed). It is NOT a malformed parameter and NOT a reason to stop: recovery is mechanical -- re-request the first page and walk forward again. There is deliberately no Retry-After and no error.retry_at, because waiting changes nothing. (2) no error.reason: an ordinary invalid request parameter -- check error.param when present, otherwise error.message. Both carry error.code=\"bad_request\" (a FROZEN contract value), so error.reason is the discriminator.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden: the credential cannot access this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "410": {
            "description": "This endpoint is retired. error.code and error.reason are endpoint_retired; error.doc_url names Edge Hunter. Stop calling this path and migrate to GET /api/v1/edge-hunter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/sports-edge-observations": {
      "get": {
        "tags": ["Markets"],
        "operationId": "listSportsEdgeObservations",
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "summary": "Retired sports edge endpoint",
        "description": "Retired permanently. Authenticated requests return 410 endpoint_retired and no sports data. Use GET /api/v1/edge-hunter?view=observations with Max to retain the full records and advanced query capabilities. Restart pagination at page one; retired route cursors cannot be reused.",
        "deprecated": true,
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["read"]
          }
        ],
        "parameters": [],
        "responses": {
          "400": {
            "description": "Bad request. On this cursor-paginated route a 400 has TWO distinct causes; branch on error.reason. (1) error.reason=\"cursor_expired\" (with error.param=\"cursor\"): the pagination cursor was invalidated by an upstream data change mid-walk (e.g. the ranking snapshot behind the page refreshed). It is NOT a malformed parameter and NOT a reason to stop: recovery is mechanical -- re-request the first page and walk forward again. There is deliberately no Retry-After and no error.retry_at, because waiting changes nothing. (2) no error.reason: an ordinary invalid request parameter -- check error.param when present, otherwise error.message. Both carry error.code=\"bad_request\" (a FROZEN contract value), so error.reason is the discriminator.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden: the credential cannot access this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. On this route a 503 has TWO distinct causes; branch on error.reason. (1) error.reason=\"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; consult that endpoint's contract and do not infer dependency health from this shared reason. This is endpoint-local unavailability, not rate limiting: retry only this route after Retry-After (or error.retry_at), and do not feed it into a rate-limit backoff shared with other endpoints. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the seconds until it probes Redis again. Both carry error.code=\"rate_limit_unavailable\" (a FROZEN contract value, so it cannot be split per cause) and X-Request-Id -- which is why error.reason, not error.code, is the discriminator.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until retrying is worth doing. With error.reason=\"read_model_warming\" this is the endpoint-local read-model retry interval; without a reason it is the rate-limiter outage cooldown. Always >= 1.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "410": {
            "description": "This endpoint is retired. error.code and error.reason are endpoint_retired; error.doc_url names Edge Hunter. Stop calling this path and migrate to GET /api/v1/edge-hunter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/coverage": {
      "get": {
        "operationId": "getCoverage",
        "summary": "Which reads the API serves for Polymarket",
        "description": "Unauthenticated discovery endpoint that declares which V1 data surfaces the API serves for Polymarket, the one venue it covers. Every capability reports supported. Coverage is sports and esports markets only (#27299): a market outside them answers 404 not_found with error.reason market_out_of_scope, and a category filter outside them answers 400 bad_request with param category on the reads that filter by it: large trades and their history, large positions, the leaderboard, market search and explore, and sharp-money flows. GET /api/v1/positions and GET /api/v1/trader/{address}/categories do not refuse a category value (#27581). Canonical since #16315; GET /api/v1/platforms is its deprecated alias with the same body.",
        "tags": ["System"],
        "security": [],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Polymarket coverage",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "platforms"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Platforms"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "platforms",
                      "data": {
                        "platforms": {
                          "polymarket": {
                            "grade": "supported",
                            "pnl": "supported",
                            "strategy": "supported",
                            "timeline": "supported",
                            "large_trades": "supported",
                            "whale_signal": "supported",
                            "suspicious_trades": "supported",
                            "insider_radar": "supported",
                            "market_snapshot": "supported"
                          }
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS 'https://api.0xinsider.com/api/v1/coverage'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "platforms",
            "data": {
              "platforms": {
                "polymarket": {
                  "grade": "supported",
                  "pnl": "supported",
                  "strategy": "supported",
                  "timeline": "supported",
                  "large_trades": "supported",
                  "whale_signal": "supported",
                  "suspicious_trades": "supported",
                  "insider_radar": "supported",
                  "market_snapshot": "supported"
                }
              }
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/platforms": {
      "get": {
        "deprecated": true,
        "operationId": "getPlatforms",
        "summary": "Get platform capability matrix",
        "description": "Deprecated since #16315: use GET /api/v1/coverage, which serves the same body. This path stays live until its sunset on 2027-02-01 (#29351) and answers with Deprecation, Sunset and successor Link headers; from that date it answers 410 Gone with error.code endpoint_retired. Unauthenticated discovery endpoint that declares which V1 data surfaces the API serves for Polymarket, the one venue it covers. Every capability reports supported. Coverage is sports and esports markets only (#27299): a market outside them answers 404 not_found with error.reason market_out_of_scope, and a category filter outside them answers 400 bad_request with param category on the reads that filter by it: large trades and their history, large positions, the leaderboard, market search and explore, and sharp-money flows. GET /api/v1/positions and GET /api/v1/trader/{address}/categories do not refuse a category value (#27581).",
        "tags": ["System"],
        "security": [],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Platform capability matrix",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "platforms"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Platforms"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "platforms",
                      "data": {
                        "platforms": {
                          "polymarket": {
                            "grade": "supported",
                            "pnl": "supported",
                            "strategy": "supported",
                            "timeline": "supported",
                            "large_trades": "supported",
                            "whale_signal": "supported",
                            "suspicious_trades": "supported",
                            "insider_radar": "supported",
                            "market_snapshot": "supported"
                          }
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Deprecation": {
                "description": "RFC 9745 structured-field date when this alias was deprecated (2026-09-23T18:00:00Z, #16315).",
                "schema": {
                  "type": "string",
                  "example": "@1790186400"
                }
              },
              "Link": {
                "description": "RFC 8288 links to the successor operation (rel=\"successor-version\") and the deprecation policy (rel=\"deprecation\").",
                "schema": {
                  "type": "string"
                }
              },
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS 'https://api.0xinsider.com/api/v1/platforms'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "platforms",
            "data": {
              "platforms": {
                "polymarket": {
                  "grade": "supported",
                  "pnl": "supported",
                  "strategy": "supported",
                  "timeline": "supported",
                  "large_trades": "supported",
                  "whale_signal": "supported",
                  "suspicious_trades": "supported",
                  "insider_radar": "supported",
                  "market_snapshot": "supported"
                }
              }
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/market/{condition_id}/holders": {
      "get": {
        "operationId": "getMarketHolders",
        "summary": "List a market's graded holders",
        "description": "The graded holder roster of one market, the list a Pick of the Day shows for its market, for any Polymarket market: every S/A/B wallet with open shares on either outcome, from a complete provider holder scan, each with its shares, Polymarket's own currentValue for the leg, its grade, its win record in the market's category, and its badges. Both outcomes are listed; a wallet holding both is listed once on its net side. Ordered by current_value_usd DESC, then shares DESC, then address. The roster is computed at most once a minute per market and shared by every caller; a page is cut from that roster, so paging is cheap and `total` is exact. An answer whose scan saw no wallet at all (`scan.wallet_count` 0), on an open market before its end date, is kept for up to an hour while no trade in that market is seen after the scan; `meta.cache_age_s` gives its age. The route never widens past the graded cohort: `scan.wallet_count` reports every wallet the walk saw, graded or not. An incomplete, unstable or failed scan is a 503 with Retry-After, never a shorter list. Cold reads are shared per account (#28752): a request for a market with no cached roster and no cached complete scan walks Polymarket, and an account may start 6 such walks a minute, in bursts of up to 400. Over that share the answer is 429 rate_limited with error.reason cold_read_limited and Retry-After, and nothing is walked; a market whose roster or scan is cached, including one another caller just read, still answers and spends no share. A complete scan in which no S, A or B wallet holds either outcome is a 200 with an empty holders list and zero totals; retrying cannot change it. The cohort is S, A and B by the wallet's current grade (`traders.latest_grade`); a C, D, F or ungraded wallet is never listed here and appears only inside `scan.wallet_count`. A count here will not match GET /api/v1/positions for the same market, and the cohort is only one of three reasons: /positions reads the `wallet_positions` mirror rather than this live provider scan, and without a `wallet` its `min_size` defaults to 100 USD, so it drops the smaller legs this route keeps. Read a difference as all three, never as a grade count. This is current state and takes no as-of parameter: the roster is at most 60 s old over a provider walk at most 180 s old (an answer with no wallet at all, at most an hour), and `scan.fetched_at` is the only timestamp on it. For a point-in-time roster, snapshot this route yourself on your own schedule; the one frozen roster the API serves is `display_holders` on GET /api/v1/pick-of-the-day, for that pick's market and backed side at publication.",
        "tags": ["Markets"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "condition_id",
            "in": "path",
            "required": true,
            "description": "Market condition ID. Accepts the raw provider-backed condition_id returned by /api/v1/markets/search or the mkt_-prefixed market.id emitted by V1 responses.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "outcome",
            "in": "query",
            "description": "Keep holders netting one side. `all` (default) lists both.",
            "schema": {
              "type": "string",
              "enum": ["yes", "no", "all"],
              "default": "all"
            }
          },
          {
            "name": "min_grade",
            "in": "query",
            "description": "Narrow within the graded cohort: `S` keeps S, `A` keeps S and A, `B` (default) keeps S, A and B. `C`, `D` and `F` are rejected with 400: the route lists the S/A/B cohort only. The cohort is the wallet's current grade (`traders.latest_grade`), so no value here reaches a C, D, F or ungraded holder; those are counted only in `scan.wallet_count`. `min_grade=D` on GET /api/v1/positions does return C and D, which is one of the three reasons the two routes' counts differ for the same market.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B"],
              "default": "B"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum holders per page. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor from the previous response's next_cursor. New cursors carry an absolute next offset bound to normalized condition_id, outcome and effective min_grade, so limit can change without skipping or repeating rows on the same roster. Different market/filter bindings return 400 bad_request with param=cursor; omitted filters match all/B and mkt_-prefixed IDs match their raw condition_id. Page-only cursors from before 2026-10-02 are no longer accepted and return 400 bad_request with param=cursor; restart without a cursor. A cursor remains valid across roster refreshes, which can still repeat or skip holders as the live roster changes.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/market/{condition_id}/holders?limit=100'"
          },
          {
            "lang": "curl",
            "label": "cURL (YES side, S and A only)",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/market/{condition_id}/holders?outcome=yes&min_grade=A'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "market": {
              "id": "mkt_example",
              "condition_id": "0x...",
              "title": "Example market",
              "category": "Soccer",
              "outcome_yes": "Yes",
              "outcome_no": "No",
              "token_id_yes": null,
              "token_id_no": null,
              "status": "open"
            },
            "scan": {
              "source": "cached",
              "complete": true,
              "fetched_at": "2026-09-21T12:00:00Z",
              "wallet_count": 0
            },
            "totals": {
              "graded_count": 0,
              "yes_count": 0,
              "no_count": 0,
              "yes_shares": 0,
              "no_shares": 0,
              "yes_usd": 0,
              "no_usd": 0,
              "yes_grades": {
                "s": 0,
                "a": 0,
                "b": 0
              },
              "no_grades": {
                "s": 0,
                "a": 0,
                "b": 0
              },
              "yes_grade_usd": {
                "s": 0,
                "a": 0,
                "b": 0
              },
              "no_grade_usd": {
                "s": 0,
                "a": 0,
                "b": 0
              }
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "responses": {
          "200": {
            "description": "One page of the market's graded holder roster.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "total",
                    "market",
                    "scan",
                    "totals",
                    "meta"
                  ],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MarketHolder"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Absent on the last page."
                    },
                    "total": {
                      "type": "integer",
                      "description": "Holders matching the request's `outcome` and `min_grade` filters across every page."
                    },
                    "market": {
                      "$ref": "#/components/schemas/MarketHoldersMarket"
                    },
                    "scan": {
                      "$ref": "#/components/schemas/MarketHoldersScan"
                    },
                    "totals": {
                      "$ref": "#/components/schemas/MarketHoldersTotals"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter, malformed cursor, or cursor belonging to a different market, outcome or effective min_grade (error.param=cursor).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27303): the market is real but outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this market. Without error.reason, no stored market has this condition_id. Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "The holder scan could not be served: the provider walk was incomplete, unstable, unavailable, or ran past its 20 s budget, or the roster's single-flight lease expired with nothing published. The body's error.reason is read_model_warming; retry after Retry-After. A shorter list is never served in place of the market.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before asking for this market's roster again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/market/{condition_id}/top-holders": {
      "get": {
        "operationId": "getMarketTopHolders",
        "summary": "List a market's top holders, every grade",
        "description": "The largest holders of one market on each outcome, every grade from S to F and ungraded wallets included: the table the market's event page shows under Top holders. Each outcome lists up to 100 wallets, largest `shares` first, from Polymarket's holder board, with the provider's current value, average entry price and position P&L for the leg, the wallet's grade, its sports and esports realized P&L and volume, its win record in the market's category, and its badges. A wallet holding both outcomes appears on each side it holds, with `other_outcome_shares` set. This is a bounded sample, not a census: `totals.yes_count` equal to `totals.sample_cap` means that many or more. For the complete S, A and B roster from a full holder scan, with exact counts and USD per grade, use GET /api/v1/market/{condition_id}/holders. The sample is the same one the event page reads and is shared by every caller. On an open market it is rebuilt at most every 30 s from Polymarket's holder board, which is itself re-read at most every 120 s, so positions are usually up to about 150 s old: `data.positions_as_of` says when that board was fetched, `data.computed_at` when the sample was built and `meta.cache_age_s` the response's age. Past the 30 s window a read gets the last sample with `data.source_stale` true while a new one builds, as long as its board is at most 300 s old; read again a few seconds later for the new sample. A resolved market's sample is at most 300 s old and has no `positions_as_of`. Busy or unavailable holder data is a 503 with Retry-After, never an empty list. Current state only; there is no as-of parameter.",
        "tags": ["Markets"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "condition_id",
            "in": "path",
            "required": true,
            "description": "Market condition ID. Accepts the raw provider-backed condition_id returned by /api/v1/markets/search or the mkt_-prefixed market.id emitted by V1 responses.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum holders per outcome. Out-of-range values are clamped to 1..100. `totals` covers the whole sample whatever the limit.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The market's largest holders on each outcome.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "market_top_holders"
                    },
                    "data": {
                      "$ref": "#/components/schemas/MarketTopHolders"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid condition_id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27303): the market is real but outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this market. Without error.reason, no stored market has this condition_id. Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "The holder sample could not be served: another request is building it and did not finish in time, or the holder read came back unavailable. The body's error.reason is read_model_warming; retry after Retry-After. An empty list is never served in its place.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before asking for this market's top holders again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/market/{condition_id}/top-holders?limit=100'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "market_top_holders",
            "data": {
              "market": {
                "id": "mkt_example",
                "condition_id": "0x...",
                "title": "Example market",
                "category": "Basketball",
                "outcome_yes": "Yes",
                "outcome_no": "No",
                "token_id_yes": null,
                "token_id_no": null,
                "status": "open"
              },
              "yes": [],
              "no": [],
              "totals": {
                "yes_count": 0,
                "no_count": 0,
                "yes_shares": 0,
                "no_shares": 0,
                "sample_cap": 100
              },
              "profiles_status": "available",
              "computed_at": "2026-11-02T12:00:00Z"
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/market/{condition_id}/flow": {
      "get": {
        "operationId": "getMarketFlow",
        "summary": "Get a market's flow and top positions",
        "description": "Canonical since #16312; GET /api/v1/market/{condition_id}/intel is its deprecated alias and serves the same body under object market_intel. One market's flow and top positions: the signed flow of every tracked large trade in the window (net_flow_usd and its YES or NO direction), the large-trade count, gross buy and sell volumes, and the top five graded trader positions.",
        "tags": ["Markets"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "condition_id",
            "in": "path",
            "required": true,
            "description": "Market condition ID. Accepts the raw provider-backed condition_id returned by /api/v1/markets/search or the mkt_-prefixed market.id emitted by V1 responses.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timeframe",
            "in": "query",
            "description": "Lookback window for whale flow aggregation.",
            "schema": {
              "type": "string",
              "enum": ["1h", "4h", "24h", "7d"],
              "default": "24h"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One market's flow and top positions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "market_flow"
                    },
                    "data": {
                      "$ref": "#/components/schemas/MarketFlow"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "market_flow",
                      "data": {
                        "market": {
                          "id": "mkt_0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                          "condition_id": "0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                          "title": "Will the Sacramento Kings win the 2025 NBA Finals?",
                          "slug": "will-the-sacramento-kings-win-the-2025-nba-finals",
                          "category": "NBA",
                          "platform": "polymarket"
                        },
                        "sharp_money": {
                          "net_flow_usd": 0,
                          "direction": "YES",
                          "token_id": "41257670817876317355997233596113195194194608207987371129645019730826567930842",
                          "large_trade_count": 0,
                          "whale_trade_count": 0,
                          "buy_volume_usd": 0,
                          "sell_volume_usd": 0,
                          "top_positions": [],
                          "oldest_snapshot_as_of": null
                        },
                        "smart_money": {
                          "net_flow_usd": 0,
                          "direction": "YES",
                          "token_id": "41257670817876317355997233596113195194194608207987371129645019730826567930842",
                          "large_trade_count": 0,
                          "whale_trade_count": 0,
                          "buy_volume_usd": 0,
                          "sell_volume_usd": 0,
                          "top_positions": [],
                          "oldest_snapshot_as_of": null
                        },
                        "timeframe": "24h"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27303): the market is real but outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this market. Without error.reason, no stored market has this condition_id. Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/market/{condition_id}/flow'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "market_flow",
            "data": {
              "market": {
                "id": "mkt_0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                "condition_id": "0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                "title": "Will the Sacramento Kings win the 2025 NBA Finals?",
                "slug": "will-the-sacramento-kings-win-the-2025-nba-finals",
                "category": "NBA",
                "platform": "polymarket"
              },
              "sharp_money": {
                "net_flow_usd": 0,
                "direction": "YES",
                "token_id": "41257670817876317355997233596113195194194608207987371129645019730826567930842",
                "large_trade_count": 0,
                "whale_trade_count": 0,
                "buy_volume_usd": 0,
                "sell_volume_usd": 0,
                "top_positions": [],
                "oldest_snapshot_as_of": null
              },
              "smart_money": {
                "net_flow_usd": 0,
                "direction": "YES",
                "token_id": "41257670817876317355997233596113195194194608207987371129645019730826567930842",
                "large_trade_count": 0,
                "whale_trade_count": 0,
                "buy_volume_usd": 0,
                "sell_volume_usd": 0,
                "top_positions": [],
                "oldest_snapshot_as_of": null
              },
              "timeframe": "24h"
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/market/{condition_id}/intel": {
      "get": {
        "operationId": "getMarketIntel",
        "summary": "Get market intelligence",
        "deprecated": true,
        "description": "Deprecated since #16312: use GET /api/v1/market/{condition_id}/flow, which serves the same body under object market_flow. This path stays live until its sunset on 2027-02-01 (#29351), keeps object market_intel, and answers with Deprecation, Sunset and successor Link headers; from that date it answers 410 Gone with error.code endpoint_retired. One market's flow and top positions: the signed flow of every tracked large trade in the window (net_flow_usd and its YES or NO direction), the large-trade count, gross buy and sell volumes, and the top five graded trader positions.",
        "tags": ["Markets"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "condition_id",
            "in": "path",
            "required": true,
            "description": "Market condition ID. Accepts the raw provider-backed condition_id returned by /api/v1/markets/search or the mkt_-prefixed market.id emitted by V1 responses.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timeframe",
            "in": "query",
            "description": "Lookback window for whale flow aggregation.",
            "schema": {
              "type": "string",
              "enum": ["1h", "4h", "24h", "7d"],
              "default": "24h"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Market intelligence",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "market_intel"
                    },
                    "data": {
                      "$ref": "#/components/schemas/MarketFlow"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "market_intel",
                      "data": {
                        "market": {
                          "id": "mkt_0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                          "condition_id": "0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                          "title": "Will the Sacramento Kings win the 2025 NBA Finals?",
                          "slug": "will-the-sacramento-kings-win-the-2025-nba-finals",
                          "category": "NBA",
                          "platform": "polymarket"
                        },
                        "sharp_money": {
                          "net_flow_usd": 0,
                          "direction": "YES",
                          "token_id": "41257670817876317355997233596113195194194608207987371129645019730826567930842",
                          "large_trade_count": 0,
                          "whale_trade_count": 0,
                          "buy_volume_usd": 0,
                          "sell_volume_usd": 0,
                          "top_positions": [],
                          "oldest_snapshot_as_of": null
                        },
                        "smart_money": {
                          "net_flow_usd": 0,
                          "direction": "YES",
                          "token_id": "41257670817876317355997233596113195194194608207987371129645019730826567930842",
                          "large_trade_count": 0,
                          "whale_trade_count": 0,
                          "buy_volume_usd": 0,
                          "sell_volume_usd": 0,
                          "top_positions": [],
                          "oldest_snapshot_as_of": null
                        },
                        "timeframe": "24h"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Deprecation": {
                "description": "RFC 9745 structured-field date when this alias was deprecated (2026-09-23T15:00:00Z, #16312).",
                "schema": {
                  "type": "string",
                  "example": "@1790175600"
                }
              },
              "Link": {
                "description": "RFC 8288 links to the successor operation (rel=\"successor-version\") and the deprecation policy (rel=\"deprecation\").",
                "schema": {
                  "type": "string"
                }
              },
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27303): the market is real but outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this market. Without error.reason, no stored market has this condition_id. Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/market/{condition_id}/intel'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "markets",
            "data": {},
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/markets/flow/batch": {
      "post": {
        "operationId": "batchGetMarketFlow",
        "summary": "Batch market flow",
        "description": "Returns each market's flow and top positions for 1-25 raw provider condition_id values. Results preserve request order, duplicate inputs return duplicate rows, and each item is charged one batch item unit before execution. Do not pass prefixed mkt_ IDs; use market.condition_id from search or explore.",
        "tags": ["Markets"],
        "requestBody": {
          "description": "Batch market-flow request. Supply 1-25 condition IDs and an optional shared timeframe.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["condition_ids"],
                "properties": {
                  "condition_ids": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 25,
                    "description": "Market condition IDs to resolve in input order.",
                    "items": {
                      "type": "string"
                    }
                  },
                  "timeframe": {
                    "type": "string",
                    "description": "Lookback window used for flow and trade-count context.",
                    "enum": ["1h", "4h", "24h", "7d"],
                    "default": "24h"
                  }
                }
              },
              "example": {
                "condition_ids": ["0x1234567890abcdef"],
                "timeframe": "24h"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ordered batch market-flow results",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Request-Cost": {
                "schema": {
                  "type": "integer"
                },
                "description": "Number of batch item units charged for this request."
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Batch-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Batch item units allowed per minute."
              },
              "X-Batch-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                },
                "description": "Batch item units remaining in the current sliding window."
              },
              "X-Batch-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Unix timestamp when the batch item window resets."
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "market_flow_batch"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BatchMarketFlowItem"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/BatchResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "market_flow_batch",
                      "data": [
                        {
                          "index": 0,
                          "input": "0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                          "status": "ok",
                          "data": {
                            "market": {
                              "id": "mkt_0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                              "condition_id": "0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                              "title": "Will the Sacramento Kings win the 2025 NBA Finals?",
                              "slug": "will-the-sacramento-kings-win-the-2025-nba-finals",
                              "category": "NBA",
                              "platform": "polymarket"
                            },
                            "sharp_money": {
                              "net_flow_usd": 0,
                              "direction": "YES",
                              "token_id": "41257670817876317355997233596113195194194608207987371129645019730826567930842",
                              "large_trade_count": 0,
                              "whale_trade_count": 0,
                              "buy_volume_usd": 0,
                              "sell_volume_usd": 0,
                              "top_positions": [],
                              "oldest_snapshot_as_of": null
                            },
                            "smart_money": {
                              "net_flow_usd": 0,
                              "direction": "YES",
                              "token_id": "41257670817876317355997233596113195194194608207987371129645019730826567930842",
                              "large_trade_count": 0,
                              "whale_trade_count": 0,
                              "buy_volume_usd": 0,
                              "sell_volume_usd": 0,
                              "top_positions": [],
                              "oldest_snapshot_as_of": null
                            },
                            "timeframe": "24h"
                          }
                        },
                        {
                          "index": 1,
                          "input": "0xdef4560000000000000000000000000000000def000000000000000000000001",
                          "status": "error",
                          "error": {
                            "code": "not_found",
                            "message": "Market 0xdef4560000000000000000000000000000000def000000000000000000000001 not found."
                          }
                        }
                      ],
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "total_items": 2,
                        "successful_items": 1,
                        "failed_items": 1,
                        "request_cost": 2,
                        "rate_limit": {
                          "basis": "batch_items_per_minute",
                          "limit": 2500,
                          "remaining": 2489,
                          "reset": 1790047440
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "The request body is over 1048576 bytes. error.code is bad_request, error.reason is payload_too_large and error.param is body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "415": {
            "description": "The body was not sent as Content-Type: application/json. error.code is bad_request, error.reason is unsupported_media_type and error.param is content-type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -X POST \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"condition_ids\":[\"0x1234567890abcdef\"],\"timeframe\":\"24h\"}' \\\n  'https://api.0xinsider.com/api/v1/markets/flow/batch'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "market_flow_batch",
            "data": [
              {
                "index": 0,
                "input": "0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                "status": "ok",
                "data": {
                  "market": {
                    "id": "mkt_0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                    "condition_id": "0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                    "title": "Will the Sacramento Kings win the 2025 NBA Finals?",
                    "slug": "will-the-sacramento-kings-win-the-2025-nba-finals",
                    "category": "NBA",
                    "platform": "polymarket"
                  },
                  "sharp_money": {
                    "net_flow_usd": 0,
                    "direction": "YES",
                    "token_id": "41257670817876317355997233596113195194194608207987371129645019730826567930842",
                    "large_trade_count": 0,
                    "whale_trade_count": 0,
                    "buy_volume_usd": 0,
                    "sell_volume_usd": 0,
                    "top_positions": [],
                    "oldest_snapshot_as_of": null
                  },
                  "smart_money": {
                    "net_flow_usd": 0,
                    "direction": "YES",
                    "token_id": "41257670817876317355997233596113195194194608207987371129645019730826567930842",
                    "large_trade_count": 0,
                    "whale_trade_count": 0,
                    "buy_volume_usd": 0,
                    "sell_volume_usd": 0,
                    "top_positions": [],
                    "oldest_snapshot_as_of": null
                  },
                  "timeframe": "24h"
                }
              },
              {
                "index": 1,
                "input": "0xdef4560000000000000000000000000000000def000000000000000000000001",
                "status": "error",
                "error": {
                  "code": "not_found",
                  "message": "Market 0xdef4560000000000000000000000000000000def000000000000000000000001 not found."
                }
              }
            ],
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "total_items": 2,
              "successful_items": 1,
              "failed_items": 1,
              "request_cost": 2,
              "rate_limit": {
                "basis": "batch_items_per_minute",
                "limit": 2500,
                "remaining": 2489,
                "reset": 1790047440
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/markets/close/batch": {
      "post": {
        "operationId": "batchGetMarketClose",
        "summary": "Batch market closing lines",
        "description": "Returns the closing line of 1-25 sports or esports markets in one request. Each ok item's data is the body GET /api/v1/market/{condition_id}/close returns for that market: status measured with both outcome legs, pending, or unavailable with unavailable_reason, judged at one clock for the whole request. Accepts raw condition_id values or mkt_-prefixed market ids. Results preserve request order, duplicate inputs return duplicate rows, and each item is charged one batch item unit before execution. A malformed id is that item's bad_request, an unknown market its not_found, and a market outside sports and esports its not_found with error.reason market_out_of_scope; the rest of the batch is served. Unknown body fields return 400.",
        "tags": ["Markets"],
        "requestBody": {
          "description": "Batch closing-line request. Supply 1-25 condition IDs.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["condition_ids"],
                "additionalProperties": false,
                "properties": {
                  "condition_ids": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 25,
                    "description": "Market condition IDs (raw or mkt_-prefixed) to resolve in input order.",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "example": {
                "condition_ids": [
                  "0x5f3a0000000000000000000000000000000000000000000000000000000000aa"
                ]
              }
            }
          }
        },
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ordered batch closing-line results",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Request-Cost": {
                "schema": {
                  "type": "integer"
                },
                "description": "Number of batch item units charged for this request."
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Batch-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Batch item units allowed per minute."
              },
              "X-Batch-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                },
                "description": "Batch item units remaining in the current sliding window."
              },
              "X-Batch-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Unix timestamp when the batch item window resets."
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "market_close_batch"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BatchMarketCloseItem"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/BatchResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "market_close_batch",
                      "data": [
                        {
                          "index": 0,
                          "input": "0x5f3a0000000000000000000000000000000000000000000000000000000000aa",
                          "status": "ok",
                          "data": {
                            "condition_id": "0x5f3a0000000000000000000000000000000000000000000000000000000000aa",
                            "status": "measured",
                            "unavailable_reason": null,
                            "game_start_time": "2026-11-02T00:20:00Z",
                            "close_anchor_at": "2026-11-02T00:20:00Z",
                            "close_anchor_source": "markets.game_start_time",
                            "anchor_stale": false,
                            "lookback_seconds": 21600,
                            "observed_at": "2026-11-02T00:19:00Z",
                            "observation_window_seconds": 60,
                            "price_source": "polymarket_data_v2_prices_history@minute-window-v1",
                            "basis_version": "data-api-v2-prices-history-resolution-v1",
                            "captured_at": "2026-11-02T06:41:12Z",
                            "outcomes": [
                              {
                                "outcome_index": 0,
                                "outcome": "Celtics",
                                "token_id": "1234",
                                "close_price": 0.575,
                                "derived_from_yes": false
                              },
                              {
                                "outcome_index": 1,
                                "outcome": "Knicks",
                                "token_id": "5678",
                                "close_price": 0.425,
                                "derived_from_yes": true
                              }
                            ]
                          }
                        },
                        {
                          "index": 1,
                          "input": "0xdef4560000000000000000000000000000000def000000000000000000000001",
                          "status": "error",
                          "error": {
                            "code": "not_found",
                            "message": "Market 0xdef4560000000000000000000000000000000def000000000000000000000001 not found."
                          }
                        }
                      ],
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "total_items": 2,
                        "successful_items": 1,
                        "failed_items": 1,
                        "request_cost": 2,
                        "rate_limit": {
                          "basis": "batch_items_per_minute",
                          "limit": 2500,
                          "remaining": 2489,
                          "reset": 1790047440
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "The request body is over 1048576 bytes. error.code is bad_request, error.reason is payload_too_large and error.param is body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "415": {
            "description": "The body was not sent as Content-Type: application/json. error.code is bad_request, error.reason is unsupported_media_type and error.param is content-type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -X POST \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"condition_ids\":[\"0x5f3a0000000000000000000000000000000000000000000000000000000000aa\"]}' \\\n  'https://api.0xinsider.com/api/v1/markets/close/batch'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "market_close_batch",
            "data": [
              {
                "index": 0,
                "input": "0x5f3a0000000000000000000000000000000000000000000000000000000000aa",
                "status": "ok",
                "data": {
                  "condition_id": "0x5f3a0000000000000000000000000000000000000000000000000000000000aa",
                  "status": "measured",
                  "unavailable_reason": null,
                  "game_start_time": "2026-11-02T00:20:00Z",
                  "close_anchor_at": "2026-11-02T00:20:00Z",
                  "close_anchor_source": "markets.game_start_time",
                  "anchor_stale": false,
                  "lookback_seconds": 21600,
                  "observed_at": "2026-11-02T00:19:00Z",
                  "observation_window_seconds": 60,
                  "price_source": "polymarket_data_v2_prices_history@minute-window-v1",
                  "basis_version": "data-api-v2-prices-history-resolution-v1",
                  "captured_at": "2026-11-02T06:41:12Z",
                  "outcomes": [
                    {
                      "outcome_index": 0,
                      "outcome": "Celtics",
                      "token_id": "1234",
                      "close_price": 0.575,
                      "derived_from_yes": false
                    },
                    {
                      "outcome_index": 1,
                      "outcome": "Knicks",
                      "token_id": "5678",
                      "close_price": 0.425,
                      "derived_from_yes": true
                    }
                  ]
                }
              },
              {
                "index": 1,
                "input": "0xdef4560000000000000000000000000000000def000000000000000000000001",
                "status": "error",
                "error": {
                  "code": "not_found",
                  "message": "Market 0xdef4560000000000000000000000000000000def000000000000000000000001 not found."
                }
              }
            ],
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "total_items": 2,
              "successful_items": 1,
              "failed_items": 1,
              "request_cost": 2,
              "rate_limit": {
                "basis": "batch_items_per_minute",
                "limit": 2500,
                "remaining": 2489,
                "reset": 1790047440
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/markets/intel/batch": {
      "post": {
        "operationId": "batchGetMarketIntel",
        "summary": "Batch market intelligence",
        "deprecated": true,
        "description": "Deprecated since #16312: use POST /api/v1/markets/flow/batch, which returns the same items under object market_flow_batch. This path stays live until its sunset on 2027-02-01 (#29351), keeps object market_intel_batch, and answers with Deprecation, Sunset and successor Link headers; from that date it answers 410 Gone with error.code endpoint_retired. Returns each market's flow and top positions for 1-25 raw provider condition_id values. Results preserve request order, duplicate inputs return duplicate rows, and each item is charged one batch item unit before execution. Do not pass prefixed mkt_ IDs; use market.condition_id from search or explore.",
        "tags": ["Markets"],
        "requestBody": {
          "description": "Batch market-intelligence request. Supply 1-25 condition IDs and an optional shared timeframe.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["condition_ids"],
                "properties": {
                  "condition_ids": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 25,
                    "description": "Market condition IDs to resolve in input order.",
                    "items": {
                      "type": "string"
                    }
                  },
                  "timeframe": {
                    "type": "string",
                    "description": "Lookback window used for flow and trade-count context.",
                    "enum": ["1h", "4h", "24h", "7d"],
                    "default": "24h"
                  }
                }
              },
              "example": {
                "condition_ids": ["0x1234567890abcdef"],
                "timeframe": "24h"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ordered batch market intelligence results",
            "headers": {
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Deprecation": {
                "description": "RFC 9745 structured-field date when this alias was deprecated (2026-09-23T15:00:00Z, #16312).",
                "schema": {
                  "type": "string",
                  "example": "@1790175600"
                }
              },
              "Link": {
                "description": "RFC 8288 links to the successor operation (rel=\"successor-version\") and the deprecation policy (rel=\"deprecation\").",
                "schema": {
                  "type": "string"
                }
              },
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Request-Cost": {
                "schema": {
                  "type": "integer"
                },
                "description": "Number of batch item units charged for this request."
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Batch-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Batch item units allowed per minute."
              },
              "X-Batch-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                },
                "description": "Batch item units remaining in the current sliding window."
              },
              "X-Batch-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Unix timestamp when the batch item window resets."
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "market_intel_batch"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BatchMarketFlowItem"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/BatchResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "market_intel_batch",
                      "data": [
                        {
                          "index": 0,
                          "input": "0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                          "status": "ok",
                          "data": {
                            "market": {
                              "id": "mkt_0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                              "condition_id": "0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                              "title": "Will the Sacramento Kings win the 2025 NBA Finals?",
                              "slug": "will-the-sacramento-kings-win-the-2025-nba-finals",
                              "category": "NBA",
                              "platform": "polymarket"
                            },
                            "sharp_money": {
                              "net_flow_usd": 0,
                              "direction": "YES",
                              "token_id": "41257670817876317355997233596113195194194608207987371129645019730826567930842",
                              "large_trade_count": 0,
                              "whale_trade_count": 0,
                              "buy_volume_usd": 0,
                              "sell_volume_usd": 0,
                              "top_positions": [],
                              "oldest_snapshot_as_of": null
                            },
                            "smart_money": {
                              "net_flow_usd": 0,
                              "direction": "YES",
                              "token_id": "41257670817876317355997233596113195194194608207987371129645019730826567930842",
                              "large_trade_count": 0,
                              "whale_trade_count": 0,
                              "buy_volume_usd": 0,
                              "sell_volume_usd": 0,
                              "top_positions": [],
                              "oldest_snapshot_as_of": null
                            },
                            "timeframe": "24h"
                          }
                        },
                        {
                          "index": 1,
                          "input": "0xdef4560000000000000000000000000000000def000000000000000000000001",
                          "status": "error",
                          "error": {
                            "code": "not_found",
                            "message": "Market 0xdef4560000000000000000000000000000000def000000000000000000000001 not found."
                          }
                        }
                      ],
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "total_items": 2,
                        "successful_items": 1,
                        "failed_items": 1,
                        "request_cost": 2,
                        "rate_limit": {
                          "basis": "batch_items_per_minute",
                          "limit": 2500,
                          "remaining": 2489,
                          "reset": 1790047440
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "The request body is over 1048576 bytes. error.code is bad_request, error.reason is payload_too_large and error.param is body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "415": {
            "description": "The body was not sent as Content-Type: application/json. error.code is bad_request, error.reason is unsupported_media_type and error.param is content-type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -X POST \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"condition_ids\":[\"0x1234567890abcdef\"],\"timeframe\":\"24h\"}' \\\n  'https://api.0xinsider.com/api/v1/markets/intel/batch'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/market/{condition_id}/snapshot": {
      "get": {
        "operationId": "getMarketSnapshot",
        "summary": "Get market live snapshot",
        "description": "Provider-first market card snapshot with canonical identity, outcome labels, cached top-of-book when available, liquidity, live sports context, and explicit freshness/unavailable states.",
        "tags": ["Markets"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "condition_id",
            "in": "path",
            "required": true,
            "description": "Market condition ID. Accepts the raw provider-backed condition_id returned by /api/v1/markets/search or /api/v1/markets/explore, or the mkt_-prefixed market.id emitted by V1 responses.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand[]",
            "in": "query",
            "required": false,
            "description": "Backward-compatible alias for expand. Repeatable: trust.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["trust"]
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "expand",
            "in": "query",
            "required": false,
            "description": "Include trust metadata for current_price and spread_bps. Repeatable: trust.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["trust"]
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Provider-first market snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "market_snapshot"
                    },
                    "data": {
                      "$ref": "#/components/schemas/MarketSnapshot"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "market_snapshot",
                      "data": {
                        "market": {
                          "id": "mkt_0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                          "condition_id": "0xabc1230000000000000000000000000000000abc2e8ec47636c7803c1033cfab",
                          "provider": "polymarket",
                          "title": "Will the Sacramento Kings win the 2025 NBA Finals?",
                          "slug": "will-the-sacramento-kings-win-the-2025-nba-finals",
                          "page_slug": "will-the-sacramento-kings-win-the-2025-nba-finals",
                          "event_slug": "nba-champion-2024-2025",
                          "category": "NBA",
                          "status": "closed",
                          "description": "This market will resolve to “Yes” if the Sacramento Kings win the 2024-2025 NBA Championship. Otherwise, this market will resolve to “No”.\n\nThis market will resolve to “No” if it becomes impossible for this team to become 2024-25 NBA Champion based off the rules of the NBA.\n\nThe resolution source for this market will be information from the NBA.",
                          "image": "https://polymarket-upload.s3.us-east-2.amazonaws.com/NBA+Team+Logos/SAC.png",
                          "series_slug": null,
                          "market_type": null,
                          "market_result": null,
                          "created_at": null,
                          "end_date": "2025-06-23T12:00:00Z",
                          "resolved_at": null
                        },
                        "outcomes": [
                          {
                            "side": "yes",
                            "label": "Yes",
                            "token_id": "41257670817876317355997233596113195194194608207987371129645019730826567930842",
                            "top_of_book": {
                              "status": "unavailable",
                              "source": "clob_best_bid_ask_cache",
                              "reason": "cache_miss"
                            }
                          },
                          {
                            "side": "no",
                            "label": "No",
                            "token_id": "6337766885333966690546293438662675059330486971861645192801950206137287554438",
                            "top_of_book": {
                              "status": "unavailable",
                              "source": "clob_best_bid_ask_cache",
                              "reason": "cache_miss"
                            }
                          }
                        ],
                        "liquidity": {
                          "last_price": null,
                          "source": "markets_read_model",
                          "volume_usd": 378011506.51,
                          "liquidity_usd": null,
                          "volume_24h_usd": null,
                          "volume_24h_as_of": null
                        },
                        "sports": {
                          "status": "stale",
                          "source": "live_sports_cache",
                          "reason": "market_not_in_stale_live_sports_read_model"
                        },
                        "settlement": {
                          "status": "observed",
                          "oracle_status": "resolved",
                          "settled": true,
                          "payouts": [0, 1000000],
                          "result": "outcome",
                          "winning_outcome_index": 1,
                          "was_disputed": false,
                          "resolved_at": "2025-06-23T14:05:11Z",
                          "expected_settlement_time": null,
                          "settlement_time_basis": null,
                          "proposed_answer": null,
                          "observed_at": "2026-11-04T05:20:00Z"
                        },
                        "freshness": {
                          "market_data": {
                            "status": "fresh",
                            "source": "markets_read_model",
                            "as_of": "2026-09-22T00:56:17.591995Z",
                            "stale_after_s": 86400
                          },
                          "top_of_book": {
                            "status": "unavailable",
                            "source": "clob_best_bid_ask_cache",
                            "reason": "cache_miss"
                          },
                          "live_sports": {
                            "status": "stale",
                            "source": "live_sports_cache",
                            "as_of": "2026-09-22T03:07:54.424925Z",
                            "reason": "live_sports_soft_ttl_expired"
                          }
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 2
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27303): the market is real but outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this market. Without error.reason, no stored market has this condition_id. Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/market/{condition_id}/snapshot'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "markets",
            "data": {},
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 2
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/market/{condition_id}/candles": {
      "get": {
        "operationId": "getMarketCandles",
        "summary": "Get market OHLC price candles",
        "description": "Provider-first bucketed OHLC price candles for a market's outcome tokens, derived from our stored copy of the Polymarket CLOB prices-history series (the same series the market-detail chart renders; covers open and resolved markets). Because the stored data is daily, a 1d bucket typically carries one point so its open/high/low/close all equal that day's close; 1w aggregates real OHLC across the observed daily closes. No intraday fidelity is fabricated. Query field names and recognized values are URL-decoded; duplicate recognized fields use the last value and unknown fields are ignored. When both bounds are present, from must be less than or equal to to; malformed or inverted bounds answer 400.",
        "tags": ["Markets"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "condition_id",
            "in": "path",
            "required": true,
            "description": "Market condition ID. Accepts the raw provider-backed condition_id returned by /api/v1/markets/search or /api/v1/markets/explore, or the mkt_-prefixed market.id emitted by V1 responses.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "resolution",
            "in": "query",
            "required": false,
            "description": "Bucketing granularity. 1d aggregates by UTC calendar day, 1w by ISO week (Monday 00:00 UTC start). Defaults to 1d.",
            "schema": {
              "type": "string",
              "enum": ["1d", "1w"],
              "default": "1d"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Exclusive lower bound as a URL-decoded unix timestamp in seconds; points at or before this timestamp are omitted (the underlying daily snapshot read filters bucket_start > from). If to is also present, from must be less than or equal to to. Note: for resolution=1w a surviving mid-week point can yield a weekly candle whose t (Monday 00:00 UTC) precedes from.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Inclusive upper bound as a URL-decoded unix timestamp in seconds; points after this timestamp are omitted. If from is also present, from must be less than or equal to to.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Provider-first market candles",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "market_candles"
                    },
                    "data": {
                      "$ref": "#/components/schemas/MarketCandles"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "market_candles",
                      "data": {
                        "condition_id": "0xcond",
                        "resolution": "1d",
                        "outcomes": [
                          {
                            "token_id": "111111",
                            "outcome": "YES",
                            "candles": [
                              {
                                "t": 1700000000,
                                "o": 0.42,
                                "h": 0.45,
                                "l": 0.41,
                                "c": 0.44
                              }
                            ]
                          }
                        ]
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 2
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27303): the market is real but outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this market. Without error.reason, no stored market has this condition_id. Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/market/{condition_id}/candles?resolution=1d'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/market/{condition_id}/close": {
      "get": {
        "operationId": "getMarketClose",
        "summary": "Get a market's closing line",
        "description": "The closing line of one sports or esports market: the price Polymarket's own price-history series recorded for each outcome in the last minute bucket that ended at or before kickoff (the market's game start time), read once after the market settles and stored unchanged. outcomes[0] is the YES leg as stored; outcomes[1] is the NO leg, 1 minus the YES price, with derived_from_yes true. It is the provider's series value: not a midpoint and not a last trade. status is measured with both legs; pending when no close is stored yet (the game has not started, the market has not settled, or the capture has not reached it; it measures markets up to 30 days after kickoff); or unavailable, with unavailable_reason, when none will be served. A missing close is never 0. anchor_stale is true when the market's kickoff has moved more than lookback_seconds since capture: the stored close belongs to the earlier kickoff. The same close measures the clv object on each large trade. Unknown condition ids return 404; markets outside sports and esports return 404 market_out_of_scope.",
        "tags": ["Markets"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "condition_id",
            "in": "path",
            "required": true,
            "description": "Market condition ID. Accepts the raw provider-backed condition_id returned by /api/v1/markets/search or /api/v1/markets/explore, or the mkt_-prefixed market.id emitted by V1 responses.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The market's closing line, or the state that says why it has none.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "market_close"
                    },
                    "data": {
                      "$ref": "#/components/schemas/MarketClose"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "example": {
                  "object": "market_close",
                  "data": {
                    "condition_id": "0x5f3a0000000000000000000000000000000000000000000000000000000000aa",
                    "status": "measured",
                    "unavailable_reason": null,
                    "game_start_time": "2026-11-02T00:20:00Z",
                    "close_anchor_at": "2026-11-02T00:20:00Z",
                    "close_anchor_source": "markets.game_start_time",
                    "anchor_stale": false,
                    "lookback_seconds": 21600,
                    "observed_at": "2026-11-02T00:19:00Z",
                    "observation_window_seconds": 60,
                    "price_source": "polymarket_data_v2_prices_history@minute-window-v1",
                    "basis_version": "data-api-v2-prices-history-resolution-v1",
                    "captured_at": "2026-11-02T06:41:12Z",
                    "outcomes": [
                      {
                        "outcome_index": 0,
                        "outcome": "Celtics",
                        "token_id": "1234",
                        "close_price": 0.575,
                        "derived_from_yes": false
                      },
                      {
                        "outcome_index": 1,
                        "outcome": "Knicks",
                        "token_id": "5678",
                        "close_price": 0.425,
                        "derived_from_yes": true
                      }
                    ]
                  },
                  "meta": {
                    "request_id": "req_example",
                    "cached": false,
                    "cost": 1
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/market/{condition_id}/wallets-in-out": {
      "get": {
        "operationId": "getMarketWalletsInOut",
        "summary": "Get a market's net buyers and sellers",
        "description": "One market's net buyers and net sellers over the last 24 hours or 7 days, live: the body the 0xinsider market page's wallets in/out panel reads for a Pro viewer, from the same aggregate and cache (reads are cached for up to 60 seconds). A wallet's net is its buys minus its sells in the window across both outcomes, in USD of matched notional, fees excluded. summary counts every wallet that traded the market in the window; net_buyers and net_sellers list the top 25 on each side. A wallet that bought and sold the same amount nets zero and is on neither list.",
        "tags": ["Markets"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "condition_id",
            "in": "path",
            "required": true,
            "description": "Market condition ID. Accepts the raw provider-backed condition_id returned by /api/v1/markets/search or /api/v1/markets/explore, or the mkt_-prefixed market.id emitted by V1 responses.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "window",
            "in": "query",
            "required": false,
            "description": "The window the nets are summed over, ending at the read's clock: 24h (the default) or 7d.",
            "schema": {
              "type": "string",
              "enum": ["24h", "7d"],
              "default": "24h"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The market's net buyers and sellers",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "market_wallets_in_out"
                    },
                    "data": {
                      "$ref": "#/components/schemas/MarketWalletsInOut"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "market_wallets_in_out",
                      "data": {
                        "condition_id": "0xcond",
                        "window": "24h",
                        "window_start": "2026-10-31T23:00:00Z",
                        "window_end": "2026-11-01T23:00:00Z",
                        "summary": {
                          "wallets_in": 412,
                          "wallets_out": 288,
                          "net_usd": 18342.57
                        },
                        "net_buyers": [
                          {
                            "address": "0x1111111111111111111111111111111111111111",
                            "display_name": "sharpwallet",
                            "grade": "A",
                            "net_usd": 52310.4,
                            "trades": 14,
                            "last_traded_at": "2026-11-01T22:58:41Z"
                          }
                        ],
                        "net_sellers": [
                          {
                            "address": "0x2222222222222222222222222222222222222222",
                            "display_name": "0x2222...2222",
                            "grade": null,
                            "net_usd": -30115.02,
                            "trades": 6,
                            "last_traded_at": "2026-11-01T22:58:41Z"
                          }
                        ]
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27303): the market is real but outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this market. Without error.reason, no stored market with a market page has this condition_id (error.param=\"condition_id\"). Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/market/{condition_id}/wallets-in-out?window=24h'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/suspicious-trades": {
      "get": {
        "operationId": "listSuspiciousTrades",
        "summary": "Get suspicious trades",
        "description": "Stored trades whose recorded suspicion score meets the live flag threshold. Evidence contains the scorer's stored signals. Cursor-paginated by suspicion score. mode=live (default) uses fresh cached pages; mode=stable pins pagination to one published scoring generation and returns cursor_expired when scores or filters change. Sports and esports markets only (#27305): a flag on a market outside product scope is not listed, and the detail route answers it 404 not_found with error.reason=market_out_of_scope. Canonical since 2026-09-23; GET /api/v1/insider-radar is its deprecated alias.",
        "tags": ["Suspicious trades"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of suspicious trades to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Pagination cursor from previous response.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_suspicion",
            "in": "query",
            "description": "Minimum suspicion score (0-100). The live flag floor of 60 also applies.",
            "schema": {
              "type": "number",
              "default": 0
            }
          },
          {
            "name": "severity",
            "in": "query",
            "description": "Compatible filter. flag selects live threshold crossings. watch returns no rows because no live watch policy exists.",
            "schema": {
              "type": "string",
              "enum": ["flag", "watch"]
            }
          },
          {
            "name": "mode",
            "in": "query",
            "description": "Pagination mode. live (default) keeps the 120-second response cache; stable pins the walk to one published scoring generation and binds the cursor to the limit and filters.",
            "schema": {
              "type": "string",
              "enum": ["live", "stable"],
              "default": "live"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Suspicious trades list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SuspiciousTrade"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total matching rows when the read model exposes a count; the key is absent when it does not."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [],
                      "has_more": false,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/insider-radar'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/suspicious-trades/{id}": {
      "get": {
        "operationId": "getSuspiciousTrade",
        "summary": "Get suspicious trade by ID",
        "description": "Returns one suspicious trade by raw whale_alerts.id or the rf_-prefixed id emitted by list responses. A flag on a market outside sports and esports returns 404 not_found with error.reason=market_out_of_scope (#27305); stop requesting it. Canonical since 2026-09-23; GET /api/v1/insider-radar/{id} is its deprecated alias and keeps answering object: radar_flag.",
        "tags": ["Suspicious trades"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Raw whale_alerts.id or rf_-prefixed suspicious trade id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Suspicious trade",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "suspicious_trade"
                    },
                    "data": {
                      "$ref": "#/components/schemas/SuspiciousTrade"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "suspicious_trade",
                      "data": {
                        "id": "rf_1042",
                        "suspicion_score": 0.83,
                        "severity": "flag",
                        "trader": {
                          "id": "trd_0xabc1230000000000000000000000000000000abc",
                          "address": "0xabc1230000000000000000000000000000000abc",
                          "username": null
                        },
                        "market": {
                          "id": "mkt_0xdef4560000000000000000000000000000000def2e8ec47636c7803c1033cfab",
                          "condition_id": "0xdef4560000000000000000000000000000000def2e8ec47636c7803c1033cfab",
                          "title": "Will the Sacramento Kings win the 2025 NBA Finals?"
                        },
                        "scores": {
                          "timing": 0.91,
                          "edge": 0.74,
                          "size": 0.62,
                          "fresh_wallet": null
                        },
                        "evidence": {
                          "first_trade_at": "2026-09-21T18:04:11Z",
                          "hours_before_close": 6.5,
                          "position_usd": 18250
                        },
                        "created_at": "2026-09-21T18:09:40Z"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27305): the flag is real but its market is outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this flag. Without error.reason, no stored flag has this id. Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/insider-radar/rf_123'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "suspicious_trade",
            "data": {},
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/games": {
      "get": {
        "operationId": "listGames",
        "summary": "List covered games",
        "description": "One coherent game view per row: both sides with their provider ids and live scores, the UTC kickoff, the provider's own status, the esports series format, and the game's winner markets (the moneyline, or a soccer game's three 1X2 legs) with their condition ids and outcome token ids. Spreads, totals, team totals, period lines and player props are on GET /api/v1/games/{event_slug}/markets. Built from the same provider-first live and upcoming projections the site's sports boards use, so a request pays no provider fan-out of its own. A finished status (ended, cancelled, postponed) also lists the games the board has dropped, from their stored records (freshness.source stored, as GET /api/v1/games/{event_slug} serves them), for kickoffs from starts_after (default 7 days before starts_before) to starts_before (default and cap: now); such a page can hold fewer than limit games, or none, while has_more is true, so follow next_cursor until has_more is false. Ordered by kickoff, then by event_slug; games whose kickoff the provider has not published sort last. For what is on now, pass window=now: without it the list starts at the oldest game still open, which can be weeks old. coverage names the sports and leagues this deployment serves and any scope whose source was unavailable for the read, so an empty page is never ambiguous. A sport outside the published vocabulary returns an empty page rather than a 400, and the response names sport in X-Query-Unmatched; a status outside its enum answers 400 invalid_query with error.param=status. Carries the board's existing competitor-bound provider moneyline price state by default, with an observation clock and explicit incomplete or invalid state. Each game also carries its traded volume (volume: value, unit, basis, source, observed_at) and each market its provider liquidity, so games can be ranked by activity without a Gamma call; a figure the board does not hold is omitted, never 0. A tennis game also carries its tournament (tier, city and country, venue time zone, official dates) from the reviewed registry its page reads, omitted when the registry holds no single edition for it. It does not fetch another provider endpoint. Soccer 1X2 moneylines retain independent YES legs classified as home, draw and away; draw_offered is true when a classified draw leg is included. The event-level sharp-money split is opt-in through expand=sharp_money (Pro and Max); holder identities remain on their own gated routes.",
        "tags": ["Games"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "sport",
            "in": "query",
            "required": false,
            "description": "Canonical sport bucket, case-insensitive, with - and _ read as a space: table-tennis and Table Tennis are the same bucket. Omit for every covered sport. A bucket this deployment does not serve returns an empty page, not an error, and the response names sport in X-Query-Unmatched; coverage.sports lists the served buckets.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "league",
            "in": "query",
            "required": false,
            "description": "League tag, case-insensitive, as this list's coverage.leagues spells it (GET /api/v1/coverage lists no leagues): nfl, epl, cs2, euroleague, cbb, cwbb. EuroLeague games use sport=Basketball and league=euroleague; NCAA men's and women's college basketball games use sport=Basketball with league=cbb and league=cwbb. Omit for every league inside the selected sports.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Keep only games in this state. ended, cancelled and postponed also list finished games that have left the live board, read from their stored records, for kickoffs within starts_after..starts_before (default: the 7 days before now). Without status, or with any other state, the list is the live and upcoming board. A value outside the enum answers 400 invalid_query with error.param=status, and its message lists the accepted values: upcoming games are scheduled.",
            "schema": {
              "type": "string",
              "enum": [
                "scheduled",
                "live",
                "paused",
                "ended",
                "postponed",
                "cancelled",
                "suspended",
                "delayed",
                "unknown"
              ]
            }
          },
          {
            "name": "starts_after",
            "in": "query",
            "required": false,
            "description": "RFC 3339 instant. Keep only games whose kickoff is at or after it. Games with no published kickoff are excluded whenever either bound is set. With a finished status, the stored games' look-back starts here; omitted, it starts 7 days before starts_before, and nothing caps an earlier value.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "starts_before",
            "in": "query",
            "required": false,
            "description": "RFC 3339 instant. Keep only games whose kickoff is at or before it. Must be at or after starts_after.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "window",
            "in": "query",
            "required": false,
            "description": "Which games to read. all, the default, lists the whole covered catalog, which can start with games the provider still holds open weeks after kickoff. now lists what is on now: every game the provider reports in play (live or paused), plus any other game whose kickoff was at most 3 hours ago or is still to come; ended, postponed and cancelled games are left out, and a game with no published kickoff stays and sorts last. Combines with every other filter. A value other than all or now returns 400 invalid_query with error.param=window.",
            "schema": {
              "type": "string",
              "enum": ["all", "now"],
              "default": "all"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque gms_v1_ cursor from next_cursor. It pins the page position (kickoff and event_slug), not a snapshot: the catalog is live, so a game added or removed between pages moves with it. With a finished status, a page that spent its read budget carries a cursor past everything it read, which may be past the last game it returned. A cursor this endpoint did not issue returns 400 with error.param=cursor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand[]",
            "in": "query",
            "required": false,
            "description": "Backward-compatible alias for expand. Repeatable: sharp_money, settlement.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["sharp_money", "settlement"]
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "expand",
            "in": "query",
            "required": false,
            "description": "sharp_money adds each game's sharp_money, the GameSharpMoney object GET /api/v1/games/{event_slug}/sharp-money returns, read from the sport board's cached aggregate: one board read per sport on the page, never a per-game compute. A game the board did not evaluate carries status not_computed (read the per-game route for it); a sport whose aggregate could not be read carries status unavailable while the rest of the page is served. Pro and Max only; adds 3 to the request cost. settlement adds settlement to each winner market, the GameMarketSettlement block GET /api/v1/games/{event_slug}/markets serves, from the same per-game store. It never waits for Polymarket: a settled market carries its recorded settlement even on a game not read lately, and any other market of such a game carries status unavailable while its read starts, so a read a moment later may answer. Every plan; adds 2 to the request cost. Repeatable; the two combine.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["sharp_money", "settlement"]
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET using a weak semantic ETag from an earlier response. A matching payload returns 304 with an empty body; request_id, cost and as_of are excluded from the validator, so a rebuilt but unchanged catalog still revalidates.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/games?sport=Soccer&status=live&limit=20'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "responses": {
          "200": {
            "description": "A page of covered games with the deployment's published coverage",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Query-Unmatched": {
                "$ref": "#/components/headers/X-Query-Unmatched"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "as_of", "coverage", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Game"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Pass as cursor for the next page. Present only when has_more is true."
                    },
                    "as_of": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When this read assembled the catalog; with status ended, cancelled or postponed, when it read the stored records. Per-source vintage is on each game's freshness."
                    },
                    "coverage": {
                      "$ref": "#/components/schemas/GamesCoverage"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "object": "game",
                      "event_slug": "nfl-buf-nyj-2026-09-22",
                      "game_id": "70898594",
                      "sport": "Football",
                      "league": "nfl",
                      "title": "Bills vs. Jets",
                      "scheduled_at": "2026-09-23T00:15:00Z",
                      "status": {
                        "state": "live",
                        "match_status": "in_progress",
                        "provider_status": "InProgress",
                        "period": "Q3",
                        "clock": "7:21",
                        "live": true,
                        "ended": false,
                        "ended_at": null,
                        "ended_at_source": null
                      },
                      "competitors": [
                        {
                          "name": "Buffalo Bills",
                          "provider_id": "2",
                          "logo": "https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl-buf.png",
                          "score": "17",
                          "record": "2-0"
                        },
                        {
                          "name": "New York Jets",
                          "provider_id": "20",
                          "logo": "https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl-nyj.png",
                          "score": "10",
                          "record": "0-2"
                        }
                      ],
                      "draw_offered": false,
                      "markets": [
                        {
                          "id": "mkt_0x2f1c0c9d5f3b4a7e8d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706",
                          "condition_id": "0x2f1c0c9d5f3b4a7e8d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706",
                          "platform": "polymarket",
                          "slug": "nfl-buf-nyj-2026-09-22",
                          "sports_market_type": "moneyline",
                          "side": "home",
                          "outcome_yes": "Buffalo Bills",
                          "outcome_no": "New York Jets",
                          "outcome_token_ids": [
                            "21742633143463906290569050155826241533067272736897614950488156847949938836455",
                            "48331043336612883890938759509493159234755048973500640148014422747788308965732"
                          ],
                          "liquidity": {
                            "value": 688004.1279,
                            "source": "gamma",
                            "observed_at": "2026-09-23T01:12:04Z"
                          }
                        }
                      ],
                      "volume": {
                        "value": 2491187.344521,
                        "unit": "taker_shares",
                        "basis": "game_lines",
                        "source": "polymarket_data",
                        "observed_at": "2026-09-23T01:11:41Z",
                        "fresh_for_seconds": 300
                      },
                      "freshness": {
                        "source": "live",
                        "source_status": "ok",
                        "source_availability": "available",
                        "source_freshness": "fresh",
                        "source_observed_at": "2026-09-23T01:12:04Z",
                        "source_age_seconds": 3,
                        "delayed": false,
                        "scores_observed_at": "2026-09-23T01:12:03Z",
                        "scores_source_at": "2026-09-23T01:12:02Z",
                        "scores_age_seconds": 4,
                        "scores_freshness": "unknown"
                      },
                      "coverage": {
                        "scores": "available",
                        "competitors": "provider_ids",
                        "schedule": "available"
                      },
                      "url": "https://0xinsider.com/event/nfl-buf-nyj-2026-09-22"
                    }
                  ],
                  "has_more": true,
                  "next_cursor": "gms_v1_eyJ2IjoxLCJyYW5rIjowLCJhdF9tcyI6MTc4OTA5NDkwMDAwMCwic2x1ZyI6Im5mbC1idWYtbnlqLTIwMjYtMDktMjIifQ",
                  "as_of": "2026-09-23T01:12:07Z",
                  "coverage": {
                    "sports": [
                      "Baseball",
                      "Basketball",
                      "Boxing",
                      "Cricket",
                      "Esports",
                      "Football",
                      "Hockey",
                      "MMA",
                      "Pickleball",
                      "Soccer",
                      "Table Tennis",
                      "Tennis"
                    ],
                    "leagues": [
                      "bel1",
                      "brasileirao",
                      "bundesliga",
                      "cfb",
                      "cs2",
                      "dota2",
                      "epl",
                      "eredivisie",
                      "laliga",
                      "leagueoflegends",
                      "ligamx",
                      "ligaprofesional",
                      "ligue1",
                      "mls",
                      "nba",
                      "nfl",
                      "nhl",
                      "primeiraliga",
                      "scop",
                      "seriea",
                      "tur",
                      "ucl",
                      "valorant",
                      "wnba"
                    ],
                    "sources_unavailable": []
                  },
                  "meta": {
                    "request_id": "req_2f8c1a4e9b3d47f0",
                    "cached": false,
                    "cost": 2
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Query-Unmatched": {
                "$ref": "#/components/headers/X-Query-Unmatched"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Bad request. error.param names the parameter: limit outside 1-100 or not an integer, starts_after or starts_before that is not an RFC 3339 instant, starts_after later than starts_before, or a cursor this endpoint did not issue. A status outside its enum or a window other than all or now answers invalid_query, with error.param=status or window. An unknown sport is not a 400: it returns an empty page and names sport in X-Query-Unmatched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Temporarily unavailable. error.reason=read_model_warming means the sports board supply did not answer this read; Retry-After is 5 seconds and the next read normally succeeds. The authenticated rate limiter being unavailable answers the same status with its own per-process cooldown.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/games/{event_slug}": {
      "get": {
        "operationId": "getGame",
        "summary": "Get one game",
        "description": "The same game object GET /api/v1/games returns, for one event_slug, including soccer 1X2 home, draw and away market sides and draw_offered. The slug is the identity the live_sports_updated webhook pulse carries, so a receiver can read the full game straight from a pulse. A slug outside the published coverage returns 404, including a real Polymarket event in a sport this deployment does not serve; GET /api/v1/games names what is covered. A finished game leaves GET /api/v1/games with the live board and stays readable here by its slug: once the provider reports it final, awarded, forfeited, cancelled or postponed, or every moneyline leg has resolved, it is served from its stored record with freshness.source stored, the final score when a live-score frame carried one, no prices, title, volume, liquidity or tournament. A game the board dropped while it was still in play returns 404. markets holds the winner markets only; GET /api/v1/games/{event_slug}/markets lists every other market of the event.",
        "tags": ["Games"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "event_slug",
            "in": "path",
            "required": true,
            "description": "The game's event slug, for example nfl-buf-nyj-2026-09-22. Matched case-insensitively.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET using a weak semantic ETag from an earlier response. A matching payload returns 304 with an empty body; request_id, cost and as_of are excluded from the validator, so a rebuilt but unchanged catalog still revalidates.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/games/nfl-buf-nyj-2026-09-22'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "responses": {
          "200": {
            "description": "One covered game",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "as_of", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "game"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Game"
                    },
                    "as_of": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When this read assembled the catalog. Per-source vintage is on freshness."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "example": {
                  "object": "game",
                  "data": {
                    "object": "game",
                    "event_slug": "nfl-buf-nyj-2026-09-22",
                    "game_id": "70898594",
                    "sport": "Football",
                    "league": "nfl",
                    "title": "Bills vs. Jets",
                    "scheduled_at": "2026-09-23T00:15:00Z",
                    "status": {
                      "state": "live",
                      "match_status": "in_progress",
                      "provider_status": "InProgress",
                      "period": "Q3",
                      "clock": "7:21",
                      "live": true,
                      "ended": false,
                      "ended_at": null,
                      "ended_at_source": null
                    },
                    "competitors": [
                      {
                        "name": "Buffalo Bills",
                        "provider_id": "2",
                        "logo": "https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl-buf.png",
                        "score": "17",
                        "record": "2-0"
                      },
                      {
                        "name": "New York Jets",
                        "provider_id": "20",
                        "logo": "https://polymarket-upload.s3.us-east-2.amazonaws.com/nfl-nyj.png",
                        "score": "10",
                        "record": "0-2"
                      }
                    ],
                    "draw_offered": false,
                    "markets": [
                      {
                        "id": "mkt_0x2f1c0c9d5f3b4a7e8d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706",
                        "condition_id": "0x2f1c0c9d5f3b4a7e8d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706",
                        "platform": "polymarket",
                        "slug": "nfl-buf-nyj-2026-09-22",
                        "sports_market_type": "moneyline",
                        "side": "home",
                        "outcome_yes": "Buffalo Bills",
                        "outcome_no": "New York Jets",
                        "outcome_token_ids": [
                          "21742633143463906290569050155826241533067272736897614950488156847949938836455",
                          "48331043336612883890938759509493159234755048973500640148014422747788308965732"
                        ],
                        "liquidity": {
                          "value": 688004.1279,
                          "source": "gamma",
                          "observed_at": "2026-09-23T01:12:04Z"
                        }
                      }
                    ],
                    "volume": {
                      "value": 2491187.344521,
                      "unit": "taker_shares",
                      "basis": "game_lines",
                      "source": "polymarket_data",
                      "observed_at": "2026-09-23T01:11:41Z",
                      "fresh_for_seconds": 300
                    },
                    "freshness": {
                      "source": "live",
                      "source_status": "ok",
                      "source_availability": "available",
                      "source_freshness": "fresh",
                      "source_observed_at": "2026-09-23T01:12:04Z",
                      "source_age_seconds": 3,
                      "delayed": false,
                      "scores_observed_at": "2026-09-23T01:12:03Z",
                      "scores_source_at": "2026-09-23T01:12:02Z",
                      "scores_age_seconds": 4,
                      "scores_freshness": "unknown"
                    },
                    "coverage": {
                      "scores": "available",
                      "competitors": "provider_ids",
                      "schedule": "available"
                    },
                    "url": "https://0xinsider.com/event/nfl-buf-nyj-2026-09-22"
                  },
                  "as_of": "2026-09-23T01:12:07Z",
                  "meta": {
                    "request_id": "req_2f8c1a4e9b3d47f0",
                    "cached": false,
                    "cost": 2
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "No covered game has that event_slug. GET /api/v1/games lists what is covered; the coverage.sports and coverage.leagues of its response say which sports and leagues this deployment serves.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Temporarily unavailable. error.reason=read_model_warming means the sports board supply did not answer this read; Retry-After is 5 seconds. The authenticated rate limiter being unavailable answers the same status with its own per-process cooldown.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/games/{event_slug}/markets": {
      "get": {
        "operationId": "listGameMarkets",
        "summary": "List a game's markets",
        "description": "Every stored Polymarket market of one event_slug: the moneyline, spreads, totals, team totals, half and quarter lines, player props and the rest, plus the markets of the event's child events (a soccer game's exact score, halftime result and more-markets events), each with its own event_slug. The game object on GET /api/v1/games carries only the winner markets the sports board binds to the two sides; this read lists the rest. Each row carries the condition_id, the provider's sports_market_type, groupItemTitle and typed line, the outcome index the line belongs to when the provider states it, both outcome labels with their CLOB token ids, active or closed status, and settlement. families lists every market type the event holds with its counts, whatever the filters. Ordered by sports_market_type, then line, then condition_id. Live, upcoming and settled events all answer. settlement is how Polymarket's oracle settled or is settling the market, read from Polymarket's /v2/resolutions and stored per game: status observed (the provider's row is below), not_posed (no oracle request yet; settled false) or unavailable (no read in hand and no recorded settlement; every other field null, and a read a moment later may answer); oracle_status, the provider lifecycle state verbatim (posed, proposed, challenged, reproposed, disputed, arbitration, resolved); settled; payouts, the provider's payout per share per outcome index in micro-USDC (1000000 is $1), only on a resolved row that carries them; result, outcome or split (Polymarket's 50-50), and winning_outcome_index, both read off payouts only; was_disputed; resolved_at; expected_settlement_time and settlement_time_basis, the provider's earliest-settlement estimate for a pending market, never a deadline; proposed_answer (outcome_0, outcome_1, split, too_early), the newest proposal of a pending round; observed_at, our clock: on a settled market when 0xinsider first saw the settlement, recorded once (each game market is read within about 30 seconds of resolving) and the same on every later read, otherwise when the provider answered the read behind the block. Every key is present; a null is unknown. A settled read is refreshed every 10 minutes, any other every minute. expand=sharp_money adds each row's sharp-money split (side USD and S, A and B wallet counts per outcome) from the game page's per-line owner: computed for a line in the game's prop frame, not_computed for a line outside it (a player prop, a line beyond the seven around its family's main line, a closed or settled line), unavailable when the read failed or held no observation of the line within 120 ms. While the frame is being built, a line the game's stored split holds is computed and dated by money_as_of. Each read starts the game's split refilling: read again after a minute or two for the lines it could not answer. expand=quotes adds each outcome's quote, the cached figures GET /api/v1/market/{condition_id}/snapshot serves, for the whole page in one cache read, on every plan, for 1 more unit of cost: status observed (the cache holds the outcome's price, its book or both; a null beside it is a figure the cache does not hold, but a null best_bid or best_ask beside a book_observed_at is a side with no orders, so a book with one side or none is observed), no_orderbook (the provider confirmed the outcome has no book and no price is cached) or unavailable (nothing cached; every figure null); price, 0 to 1, the price Polymarket shows, with price_basis midpoint (the best bid and ask are at most $0.10 apart) or last_trade, and price_observed_at, when its quote and trade state became observable; best_bid and best_ask with book_observed_at, when their CLOB frame was observed, and book_source, clob_stream (the market websocket) or clob_rest (a CLOB books read); book_depth_within_2c, the USD resting on each side within 2 cents of the midpoint (bid_usd: bids at or above the midpoint minus 0.02; ask_usd: asks at or below the midpoint plus 0.02; price times size, from the whole book, recomputed with the book), null when no depth is cached for the book; book_unavailable_reason, null when book_observed_at is set, else cache_miss, cache_unavailable, stream_capacity, no_orderbook or missing_provider_token_id. Each read keeps the page's open markets covered, so an outcome that reads cache_miss usually answers a few seconds later, as does cache_unavailable (we could not read the book from the cache this time); stream_capacity means the market is not streamed and API reads already hold every live book they may open, so it answers only once fewer markets are read. With expand=quotes the ETag moves whenever a quote does. expand=trading_terms adds each row's trading_terms, the market's terms from its Gamma record passed through unchanged, on every plan, for 1 more unit of cost: status observed (Gamma's record was read at observed_at; a null figure is one the record does not carry), not_listed (Gamma's market list returned no record for the market) or unavailable (no read in hand; every figure null); fees_enabled; fee_schedule with rate, exponent, taker_only and rebate_rate, the fraction of taker fees rebated to the resting maker; rewards_min_size, in shares, and rewards_max_spread, in cents from the midpoint; reward_allocations, the dated allocations with rewards_amount, rewards_daily_rate, start_date and end_date; seconds_delay, the delay before a newly placed marketable order can match; tick_size, the minimum price increment for limit orders; and min_order_size_shares, the smallest order the CLOB accepts, in shares (Polymarket's market reference calls this figure USDC, and the CLOB enforces it on an order's share count). Each market's read serves for a minute and then refreshes off the request path, so a market that reads unavailable usually answers a few seconds later and the ETag moves about once a minute. Without expand=quotes no price, and never a holder identity: GET /api/v1/games/{event_slug}/holders reads the holders of up to 25 of these markets in one call, and GET /api/v1/market/{condition_id}/holders or /snapshot reads one.",
        "tags": ["Games"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "event_slug",
            "in": "path",
            "required": true,
            "description": "The event slug from GET /api/v1/games, GET /api/v1/games/{event_slug} or a markets/search result's event_slug, for example nba-bos-orl-2026-11-01. Matched case-insensitively.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sports_market_type",
            "in": "query",
            "required": false,
            "description": "Comma-separated provider market types to keep, case-insensitive: spreads, totals, points, first_half_totals. Omitted keeps every type. An unknown type returns an empty page, not a 400; families lists the event's types.",
            "schema": {
              "type": "string",
              "maxLength": 512
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "active, closed or all. closed means the provider closed the market or it resolved.",
            "schema": {
              "type": "string",
              "enum": ["active", "closed", "all"],
              "default": "all"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque gmk_v1_ cursor from next_cursor, sent with the same filters. It pins the page position (sports_market_type, line, condition_id), not a snapshot. A cursor this endpoint did not issue returns 400 with error.param=cursor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand",
            "in": "query",
            "required": false,
            "description": "sharp_money adds each row's sharp_money: the game page's per-line split, side USD and S, A and B wallet counts per outcome. One read for the event whatever the page size; the request costs 5 instead of 2. Pro and Max. quotes adds each outcome's quote: the cached display price and best bid and ask, each with its observation time, in one cache read for the page; it adds 1 to the cost, on every plan. trading_terms adds each row's fee schedule, reward settings and allocations, order delay, tick and minimum order size in shares from its Gamma record, with the read's time; it adds 1 to the cost, on every plan. Repeatable: sharp_money, quotes, trading_terms.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["sharp_money", "quotes", "trading_terms"]
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "expand[]",
            "in": "query",
            "required": false,
            "description": "Backward-compatible alias for expand. Repeatable: sharp_money, quotes, trading_terms.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["sharp_money", "quotes", "trading_terms"]
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET using a weak semantic ETag from an earlier response. A matching payload returns 304 with an empty body; request_id and cost are excluded from the validator.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/games/nba-bos-orl-2026-11-01/markets?sports_market_type=spreads,totals&status=active'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "responses": {
          "200": {
            "description": "One page of the event's markets",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "event_slug", "data", "has_more", "families", "meta"],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "id",
                          "condition_id",
                          "event_slug",
                          "outcomes",
                          "status",
                          "settlement"
                        ],
                        "properties": {
                          "condition_id": {
                            "type": "string"
                          },
                          "event_slug": {
                            "type": "string"
                          },
                          "group_item_title": {
                            "type": "string"
                          },
                          "id": {
                            "type": "string"
                          },
                          "line": {
                            "type": "number"
                          },
                          "line_outcome_index": {
                            "type": "integer"
                          },
                          "negative_risk": {
                            "type": "boolean"
                          },
                          "outcomes": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "required": ["index"],
                              "properties": {
                                "index": {
                                  "type": "integer"
                                },
                                "label": {
                                  "type": "string"
                                },
                                "token_id": {
                                  "type": "string"
                                },
                                "quote": {
                                  "type": "object",
                                  "required": [
                                    "status",
                                    "price",
                                    "price_basis",
                                    "price_observed_at",
                                    "best_bid",
                                    "best_ask",
                                    "book_observed_at",
                                    "book_unavailable_reason",
                                    "book_source",
                                    "book_depth_within_2c"
                                  ],
                                  "properties": {
                                    "best_ask": {
                                      "type": ["number", "null"]
                                    },
                                    "best_bid": {
                                      "type": ["number", "null"]
                                    },
                                    "book_observed_at": {
                                      "type": ["string", "null"],
                                      "format": "date-time"
                                    },
                                    "price": {
                                      "type": ["number", "null"]
                                    },
                                    "price_basis": {
                                      "anyOf": [
                                        {
                                          "type": "string",
                                          "enum": ["midpoint", "last_trade"]
                                        },
                                        {
                                          "type": "null"
                                        }
                                      ]
                                    },
                                    "price_observed_at": {
                                      "type": ["string", "null"],
                                      "format": "date-time"
                                    },
                                    "status": {
                                      "type": "string",
                                      "enum": ["observed", "no_orderbook", "unavailable"]
                                    },
                                    "book_unavailable_reason": {
                                      "anyOf": [
                                        {
                                          "type": "string",
                                          "enum": [
                                            "cache_miss",
                                            "stream_capacity",
                                            "no_orderbook",
                                            "missing_provider_token_id",
                                            "not_streamed",
                                            "cache_unavailable"
                                          ]
                                        },
                                        {
                                          "type": "null"
                                        }
                                      ]
                                    },
                                    "book_source": {
                                      "anyOf": [
                                        {
                                          "type": "string",
                                          "enum": ["clob_stream", "clob_rest"]
                                        },
                                        {
                                          "type": "null"
                                        }
                                      ]
                                    },
                                    "book_depth_within_2c": {
                                      "anyOf": [
                                        {
                                          "type": "object",
                                          "required": ["bid_usd", "ask_usd"],
                                          "properties": {
                                            "ask_usd": {
                                              "type": "number"
                                            },
                                            "bid_usd": {
                                              "type": "number"
                                            }
                                          }
                                        },
                                        {
                                          "type": "null"
                                        }
                                      ]
                                    }
                                  }
                                }
                              }
                            }
                          },
                          "platform": {
                            "type": "string"
                          },
                          "slug": {
                            "type": "string"
                          },
                          "sports_market_type": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "sharp_money": {
                            "type": "object",
                            "required": ["status", "trader_count", "outcomes", "money_as_of"],
                            "properties": {
                              "money_as_of": {
                                "type": ["string", "null"],
                                "format": "date-time"
                              },
                              "outcomes": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "required": ["index", "usd", "wallets"],
                                  "properties": {
                                    "index": {
                                      "type": "integer"
                                    },
                                    "usd": {
                                      "type": "number"
                                    },
                                    "wallets": {
                                      "type": "object",
                                      "required": ["s", "a", "b"],
                                      "properties": {
                                        "a": {
                                          "type": "integer"
                                        },
                                        "b": {
                                          "type": "integer"
                                        },
                                        "s": {
                                          "type": "integer"
                                        }
                                      }
                                    }
                                  }
                                }
                              },
                              "status": {
                                "type": "string",
                                "enum": ["computed", "not_computed", "unavailable"]
                              },
                              "trader_count": {
                                "type": ["integer", "null"]
                              }
                            }
                          },
                          "settlement": {
                            "type": "object",
                            "required": [
                              "status",
                              "oracle_status",
                              "settled",
                              "payouts",
                              "result",
                              "winning_outcome_index",
                              "was_disputed",
                              "resolved_at",
                              "expected_settlement_time",
                              "settlement_time_basis",
                              "proposed_answer",
                              "observed_at"
                            ],
                            "properties": {
                              "expected_settlement_time": {
                                "type": ["string", "null"],
                                "format": "date-time"
                              },
                              "observed_at": {
                                "type": ["string", "null"],
                                "format": "date-time"
                              },
                              "oracle_status": {
                                "type": ["string", "null"]
                              },
                              "payouts": {
                                "type": ["array", "null"],
                                "items": {
                                  "type": "integer"
                                }
                              },
                              "proposed_answer": {
                                "anyOf": [
                                  {
                                    "type": "string",
                                    "enum": ["split", "too_early", "outcome_0", "outcome_1"]
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "resolved_at": {
                                "type": ["string", "null"],
                                "format": "date-time"
                              },
                              "result": {
                                "anyOf": [
                                  {
                                    "type": "string",
                                    "enum": ["outcome", "split"]
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "settled": {
                                "type": ["boolean", "null"]
                              },
                              "settlement_time_basis": {
                                "type": ["string", "null"]
                              },
                              "status": {
                                "type": "string",
                                "enum": ["observed", "not_posed", "unavailable"]
                              },
                              "was_disputed": {
                                "type": ["boolean", "null"]
                              },
                              "winning_outcome_index": {
                                "type": ["integer", "null"]
                              }
                            }
                          },
                          "trading_terms": {
                            "type": "object",
                            "required": [
                              "status",
                              "observed_at",
                              "fees_enabled",
                              "fee_schedule",
                              "rewards_min_size",
                              "rewards_max_spread",
                              "reward_allocations",
                              "seconds_delay",
                              "tick_size",
                              "min_order_size_shares"
                            ],
                            "properties": {
                              "fee_schedule": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "required": ["rate", "exponent", "taker_only", "rebate_rate"],
                                    "properties": {
                                      "exponent": {
                                        "type": ["number", "null"]
                                      },
                                      "rate": {
                                        "type": ["number", "null"]
                                      },
                                      "rebate_rate": {
                                        "type": ["number", "null"]
                                      },
                                      "taker_only": {
                                        "type": ["boolean", "null"]
                                      }
                                    }
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "fees_enabled": {
                                "type": ["boolean", "null"]
                              },
                              "observed_at": {
                                "type": ["string", "null"],
                                "format": "date-time"
                              },
                              "reward_allocations": {
                                "type": ["array", "null"],
                                "items": {
                                  "type": "object",
                                  "required": [
                                    "rewards_amount",
                                    "rewards_daily_rate",
                                    "start_date",
                                    "end_date"
                                  ],
                                  "properties": {
                                    "end_date": {
                                      "type": ["string", "null"]
                                    },
                                    "rewards_amount": {
                                      "type": ["number", "null"]
                                    },
                                    "rewards_daily_rate": {
                                      "type": ["number", "null"]
                                    },
                                    "start_date": {
                                      "type": ["string", "null"]
                                    }
                                  }
                                }
                              },
                              "rewards_max_spread": {
                                "type": ["number", "null"]
                              },
                              "rewards_min_size": {
                                "type": ["number", "null"]
                              },
                              "seconds_delay": {
                                "type": ["integer", "null"]
                              },
                              "status": {
                                "type": "string",
                                "enum": ["observed", "not_listed", "unavailable"]
                              },
                              "tick_size": {
                                "type": ["number", "null"]
                              },
                              "min_order_size_shares": {
                                "type": ["number", "null"]
                              }
                            }
                          }
                        }
                      }
                    },
                    "event_slug": {
                      "type": "string"
                    },
                    "families": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": ["markets", "active"],
                        "properties": {
                          "active": {
                            "type": "integer"
                          },
                          "markets": {
                            "type": "integer"
                          },
                          "sports_market_type": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "object": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "object": "list",
                  "event_slug": "nba-bos-orl-2026-11-01",
                  "data": [
                    {
                      "id": "mkt_0x49f5558b039f8528f55a2340ef1bca578d289990912e3f69e84a3a87c50a9e38",
                      "condition_id": "0x49f5558b039f8528f55a2340ef1bca578d289990912e3f69e84a3a87c50a9e38",
                      "event_slug": "nba-bos-orl-2026-11-01",
                      "platform": "polymarket",
                      "title": "Spread: Celtics (-7.5)",
                      "slug": "nba-bos-orl-2026-11-01-spread-away-7pt5",
                      "sports_market_type": "spreads",
                      "group_item_title": "Spread -7.5",
                      "line": -7.5,
                      "line_outcome_index": 0,
                      "outcomes": [
                        {
                          "index": 0,
                          "label": "Celtics",
                          "token_id": "39330833389505527007545054704572166472027203261851093602131377855263959060917"
                        },
                        {
                          "index": 1,
                          "label": "Magic",
                          "token_id": "41455195159823939239079028151913555062938922741414251339737826734240321379660"
                        }
                      ],
                      "negative_risk": false,
                      "status": "closed",
                      "settlement": {
                        "status": "observed",
                        "oracle_status": "resolved",
                        "settled": true,
                        "payouts": [1000000, 0],
                        "result": "outcome",
                        "winning_outcome_index": 0,
                        "was_disputed": false,
                        "resolved_at": "2026-11-01T23:19:04Z",
                        "expected_settlement_time": null,
                        "settlement_time_basis": null,
                        "proposed_answer": null,
                        "observed_at": "2026-11-04T03:29:29.435109Z"
                      }
                    },
                    {
                      "id": "mkt_0x0397ef87ab7d459cd00824e2705c33850dc233d72ea681ffb202b544fa0be7eb",
                      "condition_id": "0x0397ef87ab7d459cd00824e2705c33850dc233d72ea681ffb202b544fa0be7eb",
                      "event_slug": "nba-bos-orl-2026-11-01",
                      "platform": "polymarket",
                      "title": "Celtics vs. Magic: O/U 222.5",
                      "slug": "nba-bos-orl-2026-11-01-total-222pt5",
                      "sports_market_type": "totals",
                      "group_item_title": "O/U 222.5",
                      "line": 222.5,
                      "outcomes": [
                        {
                          "index": 0,
                          "label": "Over",
                          "token_id": "13003949784851430291307938878399891989617269854926595516971760558403363721196"
                        },
                        {
                          "index": 1,
                          "label": "Under",
                          "token_id": "22325872223200733324705134892670497947831011327931140737234451567978849213510"
                        }
                      ],
                      "negative_risk": false,
                      "status": "closed",
                      "settlement": {
                        "status": "observed",
                        "oracle_status": "resolved",
                        "settled": true,
                        "payouts": [0, 1000000],
                        "result": "outcome",
                        "winning_outcome_index": 1,
                        "was_disputed": false,
                        "resolved_at": "2026-11-01T23:18:48Z",
                        "expected_settlement_time": null,
                        "settlement_time_basis": null,
                        "proposed_answer": null,
                        "observed_at": "2026-11-04T03:29:29.435109Z"
                      }
                    }
                  ],
                  "has_more": true,
                  "next_cursor": "gmk_v1_eyJ2IjoxLCJ0IjoidG90YWxzIiwibCI6MjIyLjUsImMiOiIweDAzOTdlZjg3YWI3ZDQ1OWNkMDA4MjRlMjcwNWMzMzg1MGRjMjMzZDcyZWE2ODFmZmIyMDJiNTQ0ZmEwYmU3ZWIifQ",
                  "families": [
                    {
                      "sports_market_type": "moneyline",
                      "markets": 1,
                      "active": 1
                    },
                    {
                      "sports_market_type": "points",
                      "markets": 72,
                      "active": 72
                    },
                    {
                      "sports_market_type": "spreads",
                      "markets": 33,
                      "active": 33
                    },
                    {
                      "sports_market_type": "totals",
                      "markets": 31,
                      "active": 31
                    }
                  ],
                  "meta": {
                    "request_id": "req_2f8c1a4e9b3d47f0",
                    "cached": false,
                    "cost": 2
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Bad request. error.param names the parameter: limit that is not an integer, status other than active, closed or all, a sports_market_type over 512 characters, or a cursor this endpoint did not issue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\": the event is real but outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this event. Without error.reason, no stored market carries this event_slug. Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Temporarily unavailable. error.reason=database_unavailable means the market read could not reach the database; retry after Retry-After. The authenticated rate limiter being unavailable answers the same status with its own per-process cooldown.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/games/{event_slug}/sharp-money": {
      "get": {
        "operationId": "getGameSharpMoney",
        "summary": "Get one game's sharp money",
        "description": "Where the graded money sits on a whole game, in one read: the S, A and B grade wallets' USD on each outcome (home, away and, for a 1X2 game, draw) summed across the game's markets, each outcome's integer share, the leader and wallet counts by grade, with the backend's verdict on the split. It is the same aggregate the 0xinsider game page renders, so the two cannot disagree. A game the sports board did not evaluate is computed on demand; while that compute runs the route answers 503 read_model_warming with Retry-After, and the next read serves it. A settled game returns its recap with lifecycle settled. Every aggregate field is null unless status is computed: null means unknown, never zero. Pro and Max.",
        "tags": ["Games"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "event_slug",
            "in": "path",
            "required": true,
            "description": "The game's event slug, for example nba-bos-orl-2026-11-01. Matched case-insensitively; the response carries the canonical slug.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET using a weak semantic ETag from an earlier response. A matching payload returns 304 with an empty body; request_id and cost are excluded from the validator.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/games/nba-bos-orl-2026-11-01/sharp-money'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "responses": {
          "200": {
            "description": "Event-level sharp money for one game",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "game_sharp_money"
                    },
                    "data": {
                      "$ref": "#/components/schemas/GameSharpMoney"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "example": {
                  "object": "game_sharp_money",
                  "data": {
                    "object": "game_sharp_money",
                    "event_slug": "nba-bos-orl-2026-11-01",
                    "status": "computed",
                    "lifecycle": "live",
                    "verdict": {
                      "kind": "leans",
                      "label": "Celtics",
                      "pct": 68
                    },
                    "allocation": "exact",
                    "total_usd": 184250.42,
                    "unallocated_usd": 0.0,
                    "trader_count": 41,
                    "holders_partial": false,
                    "outcomes": [
                      {
                        "side": "home",
                        "label": "Magic",
                        "usd": 58960.13,
                        "pct": 32,
                        "is_leader": false,
                        "wallets": {
                          "s": 2,
                          "a": 5,
                          "b": 8
                        }
                      },
                      {
                        "side": "away",
                        "label": "Celtics",
                        "usd": 125290.29,
                        "pct": 68,
                        "is_leader": true,
                        "wallets": {
                          "s": 4,
                          "a": 9,
                          "b": 15
                        }
                      }
                    ],
                    "computed_at": "2026-11-01T22:14:05Z",
                    "money_as_of": "2026-11-01T22:12:31Z"
                  },
                  "meta": {
                    "request_id": "req_01JBX7Q4S2W8M3N5P6R7T8V9W0",
                    "cached": false,
                    "cost": 3
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "No sports game has that event_slug: no market under the slug carries a sports category. GET /api/v1/games lists covered games.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Temporarily unavailable. error.reason=read_model_warming means this game's aggregate is still being computed; read again after Retry-After (3 seconds). The authenticated rate limiter or the database being unavailable answers the same status with its own Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/games/{event_slug}/trades": {
      "get": {
        "operationId": "listGameTrades",
        "summary": "List a game's trades",
        "description": "A game's newest fills across every market in it, newest first and live: the moneyline, spreads, totals and every prop, player props included. The same rows the 0xinsider game page's activity list shows a Pro viewer, read from the same live stream. Every fill, not only large ones: GET /api/v1/large-trades?event_slug= lists the game's large trades with their review scores, and GET /api/v1/markets/sharp-money-flows?event_slug= its sharp-money flow. The list is the newest limit fills and does not page (has_more is always false); to follow a game, poll it with If-None-Match and deduplicate on id. source_stale true means the rows are the game's last complete read, served while a refresh runs; read again in a few seconds for the live rows. While a game's first read is still running the answer is 503 with error.reason read_model_warming and a Retry-After of 2 seconds.",
        "tags": ["Games"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "event_slug",
            "in": "path",
            "required": true,
            "description": "The game's event slug, for example nfl-buf-nyj-2026-09-22. Matched case-insensitively.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Newest fills to return. Out-of-range values are clamped to 1..200.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. A matching payload returns 304 Not Modified with an empty body; meta is excluded from the validator.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/games/nfl-buf-nyj-2026-09-22/trades?limit=50'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "responses": {
          "200": {
            "description": "The game's newest fills",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "event_slug", "source_stale", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "description": "Newest first.",
                      "items": {
                        "$ref": "#/components/schemas/GameTrade"
                      }
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "Always false: the list is the game's newest limit fills, not a walk. Poll again for newer fills."
                    },
                    "event_slug": {
                      "type": "string",
                      "description": "The game the rows were read for, lowercased."
                    },
                    "source_stale": {
                      "type": "boolean",
                      "description": "true when the rows are the game's last complete read, served while its refresh runs. Read again in a few seconds for the live rows."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "id": "0x8f2b6c1d4e5a7b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c:21742633143463906290569050155826241533067272736897614950488156847949938836455:0x3c5d8e1f2a4b6c7d9e0f1a2b3c4d5e6f7a8b9c0d:1500",
                      "traded_at": "2026-09-23T01:11:58Z",
                      "side": "BUY",
                      "outcome": "Buffalo Bills",
                      "outcome_index": 0,
                      "price": 0.71,
                      "shares": 1500,
                      "size_usd": 1065,
                      "point": null,
                      "trader": {
                        "address": "0x3c5d8e1f2a4b6c7d9e0f1a2b3c4d5e6f7a8b9c0d",
                        "display_name": "northshore",
                        "grade": "A"
                      },
                      "market": {
                        "id": "mkt_0x2f1c0c9d5f3b4a7e8d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706",
                        "condition_id": "0x2f1c0c9d5f3b4a7e8d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706",
                        "title": "Bills vs. Jets",
                        "slug": "nfl-buf-nyj-2026-09-22",
                        "line_label": "Moneyline"
                      }
                    }
                  ],
                  "has_more": false,
                  "event_slug": "nfl-buf-nyj-2026-09-22",
                  "source_stale": false,
                  "meta": {
                    "request_id": "req_2f8c1a4e9b3d47f0",
                    "cached": false,
                    "cost": 1
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "No game has that event_slug (error.param event_slug), or the event is outside sports and esports (error.reason market_out_of_scope, terminal). GET /api/v1/games lists covered games.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable; branch on error.reason. (1) read_model_warming: the game's first read is still running, or neither the live stream nor the provider has answered yet; retry after Retry-After (2 s). (2) database_unavailable: the API's database is briefly unreachable; retry after Retry-After (5 s). (3) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the per-process outage cooldown.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a retry is worth making.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/games/{event_slug}/holders": {
      "get": {
        "operationId": "getGameHolders",
        "summary": "Get a game's holders",
        "description": "The S, A and B graded holders of up to 25 markets of one game in one call. Each item is GET /api/v1/market/{condition_id}/holders for one market, unfiltered and cut to limit, with the same market, scan and totals beside it. Pass condition_ids from GET /api/v1/games/{event_slug}/markets; a market that is not one of the game's is that item's not_found. A batch route: results preserve request order, duplicate inputs return duplicate rows, and each requested condition_id costs one batch item unit, reserved before any item is read. Each market loads its roster as the single-market route does (a 60-second cache over a complete provider holder scan). The request waits at most 150 ms for all of them together: a market whose roster is not ready by then is an item error with code rate_limit_unavailable, reason read_model_warming and retry_at, and its scan keeps running, so a retry after that time reads the cached roster. Page a market past limit on its own holders route. Pro and Max.",
        "tags": ["Games"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "event_slug",
            "in": "path",
            "required": true,
            "description": "The game's event slug from GET /api/v1/games, for example nba-bos-orl-2026-11-01. Matched case-insensitively.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "condition_ids",
            "in": "query",
            "required": true,
            "style": "form",
            "explode": false,
            "description": "1 to 25 condition_id values of this game's markets, comma-separated. The key may also repeat (condition_ids=a&condition_ids=b). A raw provider condition_id or the mkt_-prefixed market id.",
            "schema": {
              "type": "array",
              "minItems": 1,
              "maxItems": 25,
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Holders per market. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ordered batch results, one per requested condition_id",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Request-Cost": {
                "schema": {
                  "type": "integer"
                },
                "description": "Number of batch item units charged for this request."
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Batch-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Batch item units allowed per minute."
              },
              "X-Batch-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                },
                "description": "Batch item units remaining in the current sliding window."
              },
              "X-Batch-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Unix timestamp when the batch item window resets."
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "game_holders_batch"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BatchGameHoldersItem"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/BatchResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "One ready market and one still warming",
                    "value": {
                      "object": "game_holders_batch",
                      "data": [
                        {
                          "index": 0,
                          "input": "0x5e1f0c2a9b7d4e83a6c1f2b09d8e7a6c5b4f3e2d1c0b9a8f7e6d5c4b3a291807",
                          "status": "ok",
                          "data": {
                            "data": [
                              {
                                "id": "pos_0x4b1c9a2e7d3f5a6b8c0d1e2f3a4b5c6d7e8f9a0b:0x5e1f0c2a9b7d4e83a6c1f2b09d8e7a6c5b4f3e2d1c0b9a8f7e6d5c4b3a291807:0",
                                "trader_id": "trd_0x4b1c9a2e7d3f5a6b8c0d1e2f3a4b5c6d7e8f9a0b",
                                "address": "0x4b1c9a2e7d3f5a6b8c0d1e2f3a4b5c6d7e8f9a0b",
                                "name": "courtside",
                                "side": "YES",
                                "token_id": "71321045679252212594626385532706912750332728571942532289631379312455583992563",
                                "grade": "S",
                                "shares": 18250.0,
                                "current_value_usd": 9672.5,
                                "last_traded_at": "2026-11-01T22:41:07Z",
                                "category_win_rate_status": "measured",
                                "category_win_rate": 0.6097,
                                "category_win_record": {
                                  "wins": 214,
                                  "decided": 351
                                }
                              }
                            ],
                            "has_more": true,
                            "total": 14,
                            "market": {
                              "id": "mkt_0x5e1f0c2a9b7d4e83a6c1f2b09d8e7a6c5b4f3e2d1c0b9a8f7e6d5c4b3a291807",
                              "condition_id": "0x5e1f0c2a9b7d4e83a6c1f2b09d8e7a6c5b4f3e2d1c0b9a8f7e6d5c4b3a291807",
                              "title": "Celtics vs. Magic: O/U 219.5",
                              "slug": "nba-bos-orl-2026-11-01-total-219pt5",
                              "event_slug": "nba-bos-orl-2026-11-01",
                              "category": "Sports",
                              "outcome_yes": "Over",
                              "outcome_no": "Under",
                              "token_id_yes": "71321045679252212594626385532706912750332728571942532289631379312455583992563",
                              "token_id_no": "52114319501245915516055106046884209969926127482827954674443846427813813222426",
                              "end_date": "2026-11-02T03:00:00Z",
                              "status": "open"
                            },
                            "scan": {
                              "source": "cached",
                              "complete": true,
                              "fetched_at": "2026-11-01T23:02:11Z",
                              "wallet_count": 412
                            },
                            "totals": {
                              "graded_count": 14,
                              "yes_count": 9,
                              "no_count": 5,
                              "yes_shares": 61840.0,
                              "no_shares": 20115.0,
                              "yes_usd": 32775.2,
                              "no_usd": 9454.05,
                              "yes_grades": {
                                "s": 2,
                                "a": 3,
                                "b": 4
                              },
                              "no_grades": {
                                "s": 0,
                                "a": 2,
                                "b": 3
                              },
                              "yes_grade_usd": {
                                "s": 14210.0,
                                "a": 10380.5,
                                "b": 8184.7
                              },
                              "no_grade_usd": {
                                "s": 0.0,
                                "a": 5120.3,
                                "b": 4333.75
                              }
                            },
                            "computed_at": "2026-11-01T23:02:14Z",
                            "cached": true,
                            "stale": false
                          }
                        },
                        {
                          "index": 1,
                          "input": "0x9a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b",
                          "status": "error",
                          "error": {
                            "code": "rate_limit_unavailable",
                            "message": "This read model is still warming. Retry after 3s.",
                            "reason": "read_model_warming",
                            "retry_at": "2026-11-01T23:02:20Z",
                            "doc_url": "https://docs.0xinsider.com/api-reference/introduction"
                          }
                        }
                      ],
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "total_items": 2,
                        "successful_items": 1,
                        "failed_items": 1,
                        "request_cost": 2,
                        "rate_limit": {
                          "basis": "batch_items_per_minute",
                          "limit": 2500,
                          "remaining": 2489,
                          "reset": 1790047440
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request. error.param names the parameter: condition_ids missing, empty or over 25 items, or a limit that is not an integer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\": the event is real but outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this event. Without error.reason, no stored market carries this event_slug. Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Temporarily unavailable. error.reason=database_unavailable means the market read could not reach the database; retry after Retry-After. The authenticated rate limiter being unavailable answers the same status with its own per-process cooldown.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/games/nba-bos-orl-2026-11-01/holders?condition_ids=0x5e1f...,0x9a7b...&limit=10'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/insider-radar": {
      "get": {
        "operationId": "listInsiderRadar",
        "deprecated": true,
        "summary": "Get insider radar flags",
        "description": "Deprecated alias of GET /api/v1/suspicious-trades (2026-09-23), kept live until its sunset on 2027-02-01 (#29351); responses carry Deprecation, Sunset and a Link rel=\"successor-version\" to it, and from that date the path answers 410 Gone with error.code endpoint_retired. Stored trades whose recorded suspicion score meets the live flag threshold. Evidence contains the scorer's stored signals. Cursor-paginated by suspicion score. mode=live (default) uses fresh cached pages; mode=stable pins pagination to one published scoring generation and returns cursor_expired when scores or filters change. Sports and esports markets only (#27305): a flag on a market outside product scope is not listed, and the detail route answers it 404 not_found with error.reason=market_out_of_scope.",
        "tags": ["Insider Radar"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of radar flags to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Pagination cursor from previous response.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_suspicion",
            "in": "query",
            "description": "Minimum suspicion score (0-100). The live flag floor of 60 also applies.",
            "schema": {
              "type": "number",
              "default": 0
            }
          },
          {
            "name": "severity",
            "in": "query",
            "description": "Compatible filter. flag selects live threshold crossings. watch returns no rows because no live watch policy exists.",
            "schema": {
              "type": "string",
              "enum": ["flag", "watch"]
            }
          },
          {
            "name": "mode",
            "in": "query",
            "description": "Pagination mode. live (default) keeps the 120-second response cache; stable pins the walk to one published scoring generation and binds the cursor to the limit and filters.",
            "schema": {
              "type": "string",
              "enum": ["live", "stable"],
              "default": "live"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Radar flags list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SuspiciousTrade"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total matching rows when the read model exposes a count; the key is absent when it does not."
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [],
                      "has_more": false,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Deprecation": {
                "description": "RFC 9745 structured-field date when this alias was deprecated (2026-09-23T00:00:00Z, #16301).",
                "schema": {
                  "type": "string",
                  "example": "@1790121600"
                }
              },
              "Link": {
                "description": "RFC 8288 links to the successor operation (rel=\"successor-version\") and the deprecation policy (rel=\"deprecation\").",
                "schema": {
                  "type": "string"
                }
              },
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/insider-radar'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/insider-radar/{id}": {
      "get": {
        "operationId": "getInsiderRadarFlag",
        "deprecated": true,
        "summary": "Get insider radar flag by ID",
        "description": "Deprecated alias of GET /api/v1/suspicious-trades/{id} (2026-09-23), kept live until its sunset on 2027-02-01 (#29351); responses carry Deprecation, Sunset and a Link rel=\"successor-version\" to it, and from that date the path answers 410 Gone with error.code endpoint_retired. The envelope keeps object: radar_flag, so an integration that branches on it keeps working here. Returns one suspicious-trading radar flag by raw whale_alerts.id or the rf_-prefixed id emitted by list responses. A flag on a market outside sports and esports returns 404 not_found with error.reason=market_out_of_scope (#27305); stop requesting it.",
        "tags": ["Insider Radar"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Raw whale_alerts.id or rf_-prefixed radar flag id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Radar flag",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "radar_flag"
                    },
                    "data": {
                      "$ref": "#/components/schemas/SuspiciousTrade"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "radar_flag",
                      "data": {
                        "id": "rf_1042",
                        "suspicion_score": 0.83,
                        "severity": "flag",
                        "trader": {
                          "id": "trd_0xabc1230000000000000000000000000000000abc",
                          "address": "0xabc1230000000000000000000000000000000abc",
                          "username": null
                        },
                        "market": {
                          "id": "mkt_0xdef4560000000000000000000000000000000def2e8ec47636c7803c1033cfab",
                          "condition_id": "0xdef4560000000000000000000000000000000def2e8ec47636c7803c1033cfab",
                          "title": "Will the Sacramento Kings win the 2025 NBA Finals?"
                        },
                        "scores": {
                          "timing": 0.91,
                          "edge": 0.74,
                          "size": 0.62,
                          "fresh_wallet": null
                        },
                        "evidence": {
                          "first_trade_at": "2026-09-21T18:04:11Z",
                          "hours_before_close": 6.5,
                          "position_usd": 18250
                        },
                        "created_at": "2026-09-21T18:09:40Z"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Deprecation": {
                "description": "RFC 9745 structured-field date when this alias was deprecated (2026-09-23T00:00:00Z, #16301).",
                "schema": {
                  "type": "string",
                  "example": "@1790121600"
                }
              },
              "Link": {
                "description": "RFC 8288 links to the successor operation (rel=\"successor-version\") and the deprecation policy (rel=\"deprecation\").",
                "schema": {
                  "type": "string"
                }
              },
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27305): the flag is real but its market is outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this flag. Without error.reason, no stored flag has this id. Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/insider-radar/rf_123'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "radar_flag",
            "data": {},
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/stream": {
      "get": {
        "operationId": "getStream",
        "summary": "Resumable real-time event stream (SSE)",
        "description": "Server-Sent Events stream of the live feed envelopes the platform already broadcasts (whale-trade pulses and other public/Pro feed events). Forwards the same backend-owned envelope shape as the internal feed; no provider data is recomputed. LiveScoreChanged frames may include optional live_score.tennis_points from API-Tennis in scoreboard order. This group has independent source_revision, observed_at, expires_at, set_number, and games; serving_side is omitted when unknown. Discard the group at expiry or set/game mismatch, and never compare its revision with the enclosing Polymarket score revision. Use event=LiveScoreChanged without market, wallet, grade, or size filters to receive these frames, which carry event_slug rather than condition_id. Authenticated via the oxi_sk Bearer key like every other /api/v1 endpoint, and limited to a small number of concurrent connections per API key and a cluster-wide ceiling across all keys (HTTP 429 with Retry-After when either cap is exceeded; HTTP 503 with Retry-After if a required Redis service is briefly unavailable). Each delivered frame carries an SSE id from one cluster-shared sequence that remains valid across backend replicas and process restarts. Reconnect with the Last-Event-ID header (or the last_event_id / seq query fallback) to replay the missed window before resuming live. The replay window is counted in all feed events, not in the frames a filtered connection receives: the newest 4,096 events, about 15 to 30 seconds of feed in the evening. While a connection drops frames its filter excludes, the server keeps its position, so a reconnect that sends the last delivered id after a short restart or a backend release replays from where the connection stopped instead of resyncing. A client away longer than the window gets a truncated resync; LargeTradeInsertedV2 consumers then catch up through GET /api/v1/large-trades?since= or GET /api/v1/events/feed/since. When the requested resume point is older than the retained window, ahead of the current sequence, separated from live delivery by an uncovered gap, or the server's sequence counter restarts mid-stream (a completeness.status of truncated, lagged, or reset), the stream emits a resync marker event (event: resync) instead of silently skipping frames. Idle connections receive periodic ': keep-alive' comment lines. This is a long-lived response: keep the connection open and read frames as they arrive. The server ends each response 14 minutes after it opens, before the hosting edge's 15-minute cap on any HTTP request: the body ends cleanly, with no error frame. Reconnect with Last-Event-ID set to the last id you received; the replay delivers the frames published in between. A backend release ends open streams the same way. Authorization is re-checked for as long as the stream is open: checks become due every 30 seconds and the credential cache has a 10-second TTL. Body polling and lookup I/O can delay terminal delivery. A key that is revoked, expired or rotated, or an account that is deleted, locked or no longer subscribed, ends the stream with one terminal 'event: error' frame and then closes the connection. The frame's JSON is { type: 'error', error: <the same error object a reconnect is answered with: code, message, doc_url, reason, retry_at>, retry: <boolean> }; retry is false for every credential and account refusal (a reconnect is refused with the same 401, 402, 403 or 423), and true only when the credential store stopped answering (code rate_limit_unavailable with reason database_unavailable when protected-delivery grace expires 90 seconds after the last confirmed check; terminal arrival depends on body polling), in which case reconnect after the error's retry_at with Last-Event-ID set to the frame's id to resume. Replay uses the same ongoing authorization as live delivery. When a paused response resumes, due authorization and terminal controls run before another protected replay frame is emitted; bytes already handed to HTTP cannot be recalled. A healthy response paused beyond the grace period must complete one fresh check before protected delivery resumes. Compatible unexpired tennis_points survives temporary supplemental snapshot unavailability or contention; expiry and set/game mismatch still clear it.",
        "tags": ["Streaming"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "Last-Event-ID",
            "in": "header",
            "required": false,
            "description": "Cluster-shared sequence id of the last frame the client successfully processed. The stream replays the strictly-newer retained window before resuming live, even when reconnect routing changes replicas. A future or expired id emits resync. Browser EventSource clients send this automatically on reconnect. Omit to attach live from now.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "last_event_id",
            "in": "query",
            "required": false,
            "description": "Query-string fallback for the Last-Event-ID resume cursor when the client cannot set the request header. Numeric cluster-shared sequence id; non-numeric or absent attaches live with no replay. A future or expired id emits resync.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "seq",
            "in": "query",
            "required": false,
            "description": "Alias for last_event_id. Numeric cluster-shared sequence id to resume after; non-numeric or absent attaches live with no replay. A future or expired id emits resync.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "event",
            "in": "query",
            "required": false,
            "description": "Optional per-connection subscribe-time filter. Comma-separated list of frame wire types (the SSE 'type' discriminator, e.g. WhaleTradesInserted,wallet_grade_changed); a frame passes only when its type is in the set. An unknown token returns HTTP 400 naming the offending value. An empty/all-whitespace value is treated as absent (no constraint). Applied to BOTH the replay window and live frames, and always AFTER the per-subscriber privacy gate, so it can never widen visibility beyond what the key may already see. Combines with condition_id and min_grade as a logical AND; an absent param adds no constraint.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "condition_id",
            "in": "query",
            "required": false,
            "description": "Optional per-connection subscribe-time filter. Raw provider condition_id or mkt_-prefixed market id (normalized the same way the other v1 market endpoints normalize). A frame passes only when it carries a matching condition_id field; frames that carry no condition_id (e.g. whale-pulse events) are EXCLUDED while this is set. An empty value after normalization returns HTTP 400. Combines with event and min_grade as a logical AND; an absent param adds no constraint.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_grade",
            "in": "query",
            "required": false,
            "description": "Optional per-connection subscribe-time filter. A frame passes only when it carries a grade field whose grade is better-or-equal to this minimum (S is best). On a LargeTradeInsertedV2 frame that field is grade, the wallet's grade when the trade was published: seconds after the fill for a live trade, hours after it for a backfilled one, so it is not always the grade the trade filled under. For that, send min_grade_at_trade instead. Frames without a grade (every frame except wallet_grade_changed and LargeTradeInsertedV2) are excluded. An invalid grade returns HTTP 400. Combines with the other filters as a logical AND.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"]
            }
          },
          {
            "name": "min_grade_at_trade",
            "in": "query",
            "required": false,
            "description": "Filter LargeTradeInsertedV2 frames to trades whose grade_at_trade, the grade the trader held when the trade filled, is at or above this minimum (S is best). Only a frame whose grade_at_trade_status is graded can match. The same basis as min_grade_at_trade on GET /api/v1/large-trades and on webhook trade_filters. Other event types are excluded when set. Sending it with min_grade, or an invalid grade, returns HTTP 400.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"]
            }
          },
          {
            "name": "wallet",
            "in": "query",
            "required": false,
            "description": "Filter LargeTradeInsertedV2 frames to this Polymarket wallet. Other event types have no wallet and are excluded when set. Applied to live and retained Redis frames after privacy checks.",
            "schema": {
              "type": "string",
              "pattern": "^0x[a-fA-F0-9]{40}$"
            }
          },
          {
            "name": "min_size",
            "in": "query",
            "required": false,
            "description": "Filter LargeTradeInsertedV2 frames to trades at or above this USD notional. Positive decimal with at most six places; other event types are excluded when set.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9]+(\\.[0-9]{1,6})?$"
            }
          },
          {
            "name": "league",
            "in": "query",
            "required": false,
            "description": "Filter MarketPriceMoved frames to these event slug league prefixes (comma-separated, case-insensitive, e.g. nba,epl). Other event types are excluded when set.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_move_cents",
            "in": "query",
            "required": false,
            "description": "Filter MarketPriceMoved frames to the one level step per market and window that crosses this threshold, in whole cents (2 to 50): previous_level_cents < min_move_cents <= level_cents, the market_price_moved webhook rule. Other event types are excluded when set.",
            "schema": {
              "type": "integer",
              "minimum": 2,
              "maximum": 50
            }
          },
          {
            "name": "window_seconds",
            "in": "query",
            "required": false,
            "description": "Filter MarketPriceMoved frames to moves measured over this window. Other event types are excluded when set.",
            "schema": {
              "type": "integer",
              "enum": [60, 120, 300, 900]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Open Server-Sent Events stream. The body is an unbounded text/event-stream of frames; each data frame is a JSON feed envelope (with cluster-shared seq, published_at, type, and event-specific fields) and carries an SSE id equal to seq. resync marker frames use event: resync for expired, future, lagged, sequence-reset, or otherwise uncovered cursors. A terminal event: error frame (id: <last observed seq>, data: { type: 'error', error: { code, message, ... }, retry: <boolean> }) ends the stream when the key or account it was opened with no longer authorizes it, or when the credential store has not confirmed it within 90 seconds; the connection closes after it.",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "Newline-delimited SSE frames: 'id: <seq>\\ndata: <json-envelope>\\n\\n' for events, 'event: resync\\nid: <seq>\\ndata: <json>\\n\\n' for resync markers, 'event: error\\nid: <seq>\\ndata: <json>\\n\\n' as the one terminal frame when the credential stops authorizing the stream, and ': keep-alive' comment lines while idle."
                },
                "examples": {
                  "whaleEvent": {
                    "summary": "One live whale-trade event frame",
                    "value": "id: 142\ndata: {\"seq\":142,\"published_at\":\"2026-06-04T12:00:00Z\",\"type\":\"WhaleTradesInserted\",\"count\":3}\n\n"
                  },
                  "resyncMarker": {
                    "summary": "Resync marker after a too-old resume point",
                    "value": "event: resync\nid: 9001\ndata: {\"type\":\"resync\",\"completeness\":{\"status\":\"truncated\",\"reason\":\"The requested Last-Event-ID is outside the retained replay window; treat this as a full resync and refetch current state.\"},\"from_sequence\":12,\"to_sequence\":9001}\n\n"
                  },
                  "credentialRevoked": {
                    "summary": "Terminal error frame after the key was revoked mid-stream; the connection closes after it",
                    "value": "event: error\nid: 9120\ndata: {\"type\":\"error\",\"error\":{\"code\":\"invalid_api_key\",\"message\":\"The API key this stream was opened with is no longer valid (revoked, expired or rotated). The stream is closed; a reconnect with it is refused with 401 invalid_api_key.\",\"doc_url\":\"https://docs.0xinsider.com/api-reference/introduction#authentication\"},\"retry\":false}\n\n"
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "A required Redis-backed admission or shared replay service is unavailable; retry after the outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -N -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/stream'"
          },
          {
            "lang": "curl",
            "label": "cURL (resume)",
            "source": "curl -N -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  -H 'Last-Event-ID: 100' \\\n  'https://api.0xinsider.com/api/v1/stream'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/events/feed/since": {
      "get": {
        "operationId": "getEventReplaySince",
        "summary": "Replay public large-trade events",
        "description": "Returns durable public large-trade events strictly after an opaque cursor, in commit order: events are ordered by the position at which their write became visible to every reader (whale_alerts.inserted_xid), then by whale_alerts.id, and a page never reaches past the oldest write transaction still open when it was read. A trade whose id is lower than one already delivered but whose write finished later is therefore delivered on a later request instead of being skipped (#16180). This is a separate API-key contract from the browser/session /api/events/feed stream: browser-only and private alert, following, radar, and position patch events are excluded until they have a durable public outbox. Carries large trades on sports and esports markets only (#27430).",
        "tags": ["Events"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque event replay cursor returned as next_cursor by a prior response. The cursor maps to the global (whale_alerts.inserted_xid, whale_alerts.id) commit-order position, is valid across backend replicas, and is bound to every filter the walk ran with (trader, condition_id, min_grade, min_grade_at_trade, min_size; expand is not a filter): presenting it under different filters, including a switch between min_grade and min_grade_at_trade, answers 400 bad_request with error.reason cursor_expired, and the walk restarts without a cursor. Cursors issued before 2026-09-22 (id-only) stay accepted and are bound to no filters. Omit to fetch the latest durable public suffix.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum durable public whale-trade events to return. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "trader",
            "in": "query",
            "required": false,
            "description": "Only this wallet's trades: a wallet address, trd_-prefixed trader id or username resolved against the traders table. Bound to the cursor: a cursor issued under other filters answers 400 with error.reason cursor_expired. An unknown trader matches nothing and the walk still advances.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "condition_id",
            "in": "query",
            "required": false,
            "description": "Only trades on this market: the raw provider condition_id or its mkt_-prefixed id. Bound to the cursor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_grade",
            "in": "query",
            "required": false,
            "description": "Only trades by wallets at this grade or better (S best), read from the wallet's newest ranking at request time; a wallet with no grade never passes. For the grade the wallet held when the trade filled, send min_grade_at_trade instead. Bound to the cursor.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"]
            }
          },
          {
            "name": "min_grade_at_trade",
            "in": "query",
            "required": false,
            "description": "Only trades whose grade_at_trade, the grade the wallet held when the trade filled, is at this grade or better (S best). Only a trade whose grade at the fill is graded passes, so a trade before 2026-09-19T23:00Z, or one made while the wallet's grade was changing, never does. The same basis as min_grade_at_trade on GET /api/v1/large-trades, GET /api/v1/stream and webhook trade_filters. Bound to the cursor: switching between min_grade and min_grade_at_trade is a filter change and answers cursor_expired. Sending it with min_grade, or an invalid grade, returns HTTP 400.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B", "C", "D", "F"]
            }
          },
          {
            "name": "min_size",
            "in": "query",
            "required": false,
            "description": "Only trades of at least this USD amount. Decimal and scientific query spellings normalize exactly to cents, rounding half away from zero; maximum 1e15 USD. Pass the dataset continuation decimal string unchanged to preserve the bound. Bound to the cursor.",
            "schema": {
              "oneOf": [
                {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1000000000000000.0
                },
                {
                  "type": "string",
                  "description": "Exact decimal query spelling, including scientific notation."
                }
              ]
            }
          },
          {
            "name": "expand[]",
            "in": "query",
            "required": false,
            "description": "Backward-compatible alias for expand. Repeatable: trade.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["trade"]
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "expand",
            "in": "query",
            "required": false,
            "description": "Repeatable. trade adds the public trade read to every event (the object GET /api/v1/whale-trades/{id} returns for it), from one query per page, so a page of 100 events needs no per-event detail request. Not bound to the cursor: switch it on or off mid-walk.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["trade"]
              }
            },
            "style": "form",
            "explode": true
          }
        ],
        "responses": {
          "200": {
            "description": "Public event replay window",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "next_cursor", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "event_replay"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EventReplayEvent"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/EventReplayMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "event_replay",
                      "data": [],
                      "has_more": false,
                      "next_cursor": "ZWYyXzBfMA",
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1,
                        "replay": {
                          "from_cursor": "ZWYyXzBfMA",
                          "to_cursor": "ZWYyXzBfMA",
                          "from_sequence": 0,
                          "to_sequence": 0,
                          "ordering": "commit_visibility_then_id_asc",
                          "pending_beyond_horizon": false,
                          "expand": []
                        },
                        "retention": {
                          "status": "durable_database",
                          "retained_events": 0,
                          "cursor_expired": false
                        },
                        "completeness": {
                          "status": "caught_up",
                          "reason": "No durable public whale-trade events were found after the requested cursor."
                        }
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter, or (error.reason cursor_expired, param cursor) a cursor presented under a filter set other than the one it was issued with: restart without a cursor under the new filters and continue with next_cursor.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/events/feed/since'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "events",
            "data": {},
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "summary": "List builder webhook destinations",
        "description": "Returns webhook destinations owned by the authenticated API key user. Deleted endpoints are omitted; an endpoint paused with PATCH or disabled after consecutive failures is listed with status disabled. Subscribable event_types and their payload shapes are described by GET /api/v1/webhooks/events. Export lifecycle event types (export_job_ready, export_job_failed, export_job_expired, export_job_cancelled) are delivered only to the API-key account that created the export and contain no download URL; use the authorized export status and download routes. Four subscribable event types are Pro-only and only deliver to API keys on an active Pro subscription. whale_trades_inserted is one of them, gated by the same SubscriberScope::InsiderOnly mechanism as the other three (each type carries its own LiveEventContract entry; they share the scope value). The other three: wallet_grade_changed (data: wallet, trader_id, old_grade, new_grade, direction (upgrade|downgrade), skill_index, final_score, date) fires on a Pass-2 grade transition; insider_radar_flag_raised (data: trade_id, wallet, trader_id, condition_id, suspicion_score, track, side (yes|no), size, price) fires the first time a trade's suspicion score crosses the radar flag threshold; sharp_money_flow_detected (data: condition_id, net_flow_usd, abs_net_flow_usd, dominant_side (yes|no), grade_floor (S|A|B|C|D|F), whale_trade_count, window) fires when a scheduled scanner detects ranked-trader net flow crossing a threshold (up or down) on a market, and smart_money_flow_detected is its deprecated spelling of the same event. live_sports_updated (data: event_slug, game_id, league, version, changed, observed_at, published_at, status, period, clock, live, ended, scores, series_format, snapshot_url) is ungated and fires as a bounded per-game pulse when a live game's scores, status, period or live/ended state moves: at most one delivery per game per 20 seconds, with a live or ended transition exempt from that interval, and the game clock alone never firing one. version is a durable per-game ordinal, changed lists the material fields that moved since that game's previous delivered pulse, and snapshot_url is where to re-read the whole game after a gap.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook destination list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookEndpoint"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "One registered endpoint",
                    "value": {
                      "object": "list",
                      "data": [
                        {
                          "id": 1,
                          "object": "webhook",
                          "name": "Production webhook",
                          "url": "https://example.com/0xinsider/webhook",
                          "event_types": ["whale_trades_inserted"],
                          "trade_filters": {},
                          "price_move_filters": null,
                          "status": "pending_verification",
                          "verified_at": null,
                          "verification_token_expires_at": "2026-09-23T03:14:44.903437Z",
                          "failure_count": 0,
                          "created_at": "2026-09-22T03:14:42.182366Z",
                          "updated_at": "2026-09-22T03:14:42.182366Z",
                          "retry_policy": {
                            "max_attempts": 8,
                            "terminal_status": "dead_letter",
                            "retry_horizon_seconds": 7380,
                            "disable_after_consecutive_failures": 8
                          },
                          "secret_rotation": {
                            "status": "idle",
                            "overlap_expires_at": null
                          }
                        }
                      ],
                      "has_more": false,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/webhooks'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [
              {
                "id": 1,
                "object": "webhook",
                "name": "Production webhook",
                "url": "https://example.com/0xinsider/webhook",
                "event_types": ["whale_trades_inserted"],
                "status": "pending_verification"
              }
            ],
            "has_more": false,
            "next_cursor": null,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["webhooks"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      },
      "post": {
        "operationId": "createWebhook",
        "summary": "Create a builder webhook destination",
        "description": "Creates a pending HTTPS webhook destination. The response includes one-time signing_secret and verification.token values. Deliveries are not sent until the endpoint is verified, and verification requires the destination to answer 2xx to a signed webhook.verification challenge (see POST /api/v1/webhooks/{id}/verify). The subscribable event_types and their data payload shapes are described by GET /api/v1/webhooks/events; the per-endpoint delivery log is GET /api/v1/webhooks/{id}/deliveries. Export lifecycle event types (export_job_ready, export_job_failed, export_job_expired, export_job_cancelled) are delivered only to the API-key account that created the export and contain no download URL; use the authorized export status and download routes. Four subscribable event types are Pro-only and only deliver to API keys on an active Pro subscription. whale_trades_inserted is one of them, gated by the same SubscriberScope::InsiderOnly mechanism as the other three (each type carries its own LiveEventContract entry; they share the scope value). The other three: wallet_grade_changed (data: wallet, trader_id, old_grade, new_grade, direction (upgrade|downgrade), skill_index, final_score, date) fires on a Pass-2 grade transition; insider_radar_flag_raised (data: trade_id, wallet, trader_id, condition_id, suspicion_score, track, side (yes|no), size, price) fires the first time a trade's suspicion score crosses the radar flag threshold; sharp_money_flow_detected (data: condition_id, net_flow_usd, abs_net_flow_usd, dominant_side (yes|no), grade_floor (S|A|B|C|D|F), whale_trade_count, window) fires when a scheduled scanner detects ranked-trader net flow crossing a threshold (up or down) on a market, and smart_money_flow_detected is its deprecated spelling of the same event. live_sports_updated (data: event_slug, game_id, league, version, changed, observed_at, published_at, status, period, clock, live, ended, scores, series_format, snapshot_url) is ungated and fires as a bounded per-game pulse when a live game's scores, status, period or live/ended state moves: at most one delivery per game per 20 seconds, with a live or ended transition exempt from that interval, and the game clock alone never firing one. version is a durable per-game ordinal, changed lists the material fields that moved since that game's previous delivered pulse, and snapshot_url is where to re-read the whole game after a gap. Delivery signing: each delivery request carries one or more HMAC-SHA256 signatures in the x-0xinsider-signature header as comma-separated v1=<hex> candidates. During staged rotation, the current and previous signing secrets are both signed for one hour; while 0xinsider rotates the key every signing secret is derived from, each also signs under the previous key, so the secret you hold keeps verifying. Up to four candidates; accept any valid candidate. Each candidate is HMAC-SHA256(signing_secret, \"<timestamp>.<raw_request_body>\"). The signed <timestamp> is sent separately as x-0xinsider-timestamp (unix seconds). To verify a delivery: read x-0xinsider-timestamp, reject it if it differs from the current time by more than 300 seconds, recompute each candidate over \"<timestamp>.<raw_body>\" with the active secrets, and compare using a constant-time comparison. Each delivery also carries x-0xinsider-event-id, x-0xinsider-event-type, x-0xinsider-delivery-id, and x-0xinsider-delivery-attempt headers. Retries and disabling: ordinary transient delivery failures use stable jitter between half and the existing 60, 120, 240, 480, 960, 1920 and 3600-second upper bounds (retry_policy.retry_horizon_seconds = 7380); on 408, 429, or 5xx, a valid Retry-After delta-seconds or HTTP-date replaces that one wait and is clamped to 60–3600 seconds, while missing, malformed, past, or non-retryable-response hints use the ordinary schedule. The delivery still has eight attempts (retry_policy.max_attempts), and an eighth failure becomes dead_letter. The delivery log exposes retry_schedule_reason and next_attempt_at so a receiver can see the active schedule. Separately, an endpoint is disabled after 8 consecutive failed attempts across all of its deliveries (retry_policy.disable_after_consecutive_failures); any successful attempt resets that count, so a busy endpoint that goes down can be disabled in minutes, well before any single delivery exhausts its retries. Disabling dead-letters every delivery still queued for the endpoint and emails the account owner, within about an hour, with each disabled endpoint and its last failed response. Re-enable it with PATCH /api/v1/webhooks/{id} {\"enabled\": true}; re-enabling does not resend dead-lettered deliveries. Resend each one with POST /api/v1/webhooks/{id}/deliveries/{delivery_id}/redeliver, or catch up with GET /api/v1/events/feed/since from the last event you processed. GET /api/v1/webhooks/{id}/deliveries shows next_attempt_at and retry_schedule_reason for a delivery still waiting to retry.",
        "tags": ["Webhooks"],
        "requestBody": {
          "description": "Webhook destination to create.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookRequest"
              },
              "example": {
                "name": "Production webhook",
                "url": "https://example.com/0xinsider/webhook",
                "event_types": ["whale_trades_inserted"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook destination",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "webhook"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookEndpoint"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Endpoint registered, verification pending",
                    "value": {
                      "data": {
                        "created_at": "2026-09-22T03:14:42.182366Z",
                        "event_types": ["whale_trades_inserted"],
                        "trade_filters": {},
                        "price_move_filters": null,
                        "failure_count": 0,
                        "id": 1,
                        "name": "Production webhook",
                        "object": "webhook",
                        "retry_policy": {
                          "disable_after_consecutive_failures": 8,
                          "max_attempts": 8,
                          "retry_horizon_seconds": 7380,
                          "terminal_status": "dead_letter"
                        },
                        "secret_rotation": {
                          "status": "idle",
                          "overlap_expires_at": null
                        },
                        "signing_secret": "whsec_kDENj63HXaudBJsBQ8tB1PHGXOBq-J1CK2VzgX8awCs",
                        "status": "pending_verification",
                        "updated_at": "2026-09-22T03:14:42.182366Z",
                        "url": "https://example.com/0xinsider/webhook",
                        "verification": {
                          "expires_at": "2026-09-23T03:14:44.903437Z",
                          "token": "whv_88d8b0dcedeb401091fd4d44e26cc7a1"
                        },
                        "verification_token_expires_at": "2026-09-23T03:14:44.903437Z",
                        "verified_at": null
                      },
                      "meta": {
                        "cached": false,
                        "cost": 1,
                        "request_id": "req_example"
                      },
                      "object": "webhook"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "The request body is over 1048576 bytes. error.code is bad_request, error.reason is payload_too_large and error.param is body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "415": {
            "description": "The body was not sent as Content-Type: application/json. error.code is bad_request, error.reason is unsupported_media_type and error.param is content-type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "An Idempotency-Key request with the same body is still in progress. Retry shortly with the same key and body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "in_progress": {
                    "summary": "Idempotency request still in progress",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "bad_request",
                        "message": "Your previous request is still processing. Retry in a moment.",
                        "param": "Idempotency-Key",
                        "reason": "idempotency_in_progress"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The Idempotency-Key was already used with a different request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "different_body": {
                    "summary": "Idempotency key reused with a different body",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "bad_request",
                        "message": "Idempotency-Key already used with a different request body",
                        "param": "Idempotency-Key"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -X POST \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"name\":\"Production webhook\",\"url\":\"https://example.com/0xinsider/webhook\",\"event_types\":[\"whale_trades_inserted\"]}' \\\n  'https://api.0xinsider.com/api/v1/webhooks'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "webhook",
            "data": {
              "id": 1,
              "object": "webhook",
              "name": "Production webhook",
              "url": "https://example.com/0xinsider/webhook",
              "event_types": ["whale_trades_inserted"],
              "status": "pending_verification"
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional safe-retry key. Reuse the same value only when retrying the exact same mutation request body; a different body returns 422 and an in-flight matching request returns 409.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255
            },
            "example": "wh_idem_01HX7Y9ZQ4K7Z0Q2E4N6A8C1BF"
          }
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["webhooks"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/webhooks/events": {
      "get": {
        "operationId": "listWebhookEvents",
        "summary": "List webhook event catalog",
        "description": "Self-describing catalog of every webhook event type: its description, data payload shape, and whether it is active (has a firing producer) or dormant (subscribable but not yet delivered; no event type is dormant today). The catalog is identical for every authenticated key and exposes no owner-scoped data. Pro-only event types (large_trades_inserted, whale_trades_inserted, wallet_grade_changed, suspicious_trade_flagged, insider_radar_flag_raised, sharp_money_flow_detected, smart_money_flow_detected) appear in the catalog but only deliver to API keys on an active Pro subscription. Export lifecycle event types (export_job_ready, export_job_failed, export_job_expired, export_job_cancelled) are owner-scoped to the API-key account that created the export and contain no download URL; use the authorized export status and download routes.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook event catalog",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookEventDescriptor"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [
                        {
                          "id": "whale_trades_inserted",
                          "description": "Fires when new whale-sized trades are ingested.",
                          "payload_shape": "{ count: integer }",
                          "status": "active"
                        }
                      ],
                      "has_more": false,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/webhooks/events'"
          }
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["webhooks"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/webhooks/{id}/deliveries": {
      "get": {
        "operationId": "listWebhookDeliveries",
        "summary": "List webhook delivery log",
        "description": "Recent delivery attempts for one webhook destination owned by the authenticated API key user, newest first, with opaque cursor pagination. Returns 404 (identical to an unknown id) when the endpoint is not owned by the caller, so a non-owner cannot tell an owned-but-empty log apart from someone else's endpoint. Delivery rows omit the request body and signing secret. next_attempt_at is when a pending or retry delivery is next attempted; retry_schedule_reason says whether the queue is following receiver_retry_after, transient_failure, permanent_or_auth_failure, manual_redelivery, or configuration_changed; both are null while an attempt is in flight and once the delivery is delivered or dead_letter. A delivery keeps the existing eight-attempt budget, endpoint failure budget, fairness limits, and ordinary 7380-second upper-bound schedule; see POST /api/v1/webhooks for the bounded Retry-After policy. Resend a dead_letter delivery with POST /api/v1/webhooks/{id}/deliveries/{delivery_id}/redeliver.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhook endpoint id owned by the authenticated API key user.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque pagination cursor returned as next_cursor by a prior response. Omit to fetch the newest page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum delivery rows to return per page. Out-of-range values are clamped to 1..100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook delivery log page",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "has_more", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookDelivery"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "list",
                      "data": [
                        {
                          "id": 1,
                          "object": "webhook_delivery",
                          "event_id": "evt_whale_trades_inserted_1700000000_3",
                          "event_type": "whale_trades_inserted",
                          "status": "delivered",
                          "attempt_count": 1,
                          "last_response_status": 200,
                          "delivered_at": "2026-06-04T12:00:00Z",
                          "next_attempt_at": null,
                          "retry_schedule_reason": null,
                          "created_at": "2026-06-04T12:00:00Z"
                        }
                      ],
                      "has_more": false,
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/webhooks/123/deliveries'"
          }
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["webhooks"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/webhooks/{id}/deliveries/{delivery_id}/redeliver": {
      "post": {
        "operationId": "redeliverWebhookDelivery",
        "summary": "Redeliver a dead-lettered webhook delivery",
        "description": "Returns one dead_letter delivery to the delivery queue with a fresh attempt budget: status becomes pending, attempt_count resets to 0, and next_attempt_at is now, so the delivery worker claims it like any queued delivery, under the same per-owner and per-origin concurrency limits. Use it after a failed delivery exhausts its retries, or after re-enabling an endpoint whose queued deliveries were dead-lettered when it was disabled: PATCH /api/v1/webhooks/{id} {\"enabled\": true} resends nothing by itself. The resend is signed with the endpoint's current signing secret and sent to its current URL, and keeps the delivery's event_id and idempotency-key header, so a receiver that already processed the event can deduplicate it; x-0xinsider-delivery-attempt starts again at 1. last_response_status and last_error keep the previous failure until the next attempt records its own. Returns 409 when the delivery is already delivered or still queued (pending, retry, or processing), or when the endpoint would not receive it (disabled, not verified, or no longer subscribed to the delivery's event_type); error.message names the step that lets the same request succeed. Returns 404 for an endpoint or delivery the caller does not own, including a delivery removed by the seven-day retention of delivered and dead_letter history.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhook endpoint id owned by the authenticated API key user.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "delivery_id",
            "in": "path",
            "required": true,
            "description": "Delivery id from GET /api/v1/webhooks/{id}/deliveries. It must belong to the webhook endpoint named by id.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional safe-retry key. Reuse the same value only when retrying the exact same mutation request body; a different body returns 422 and an in-flight matching request returns 409.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255
            },
            "example": "wh_idem_01HX7Y9ZQ4K7Z0Q2E4N6A8C1BF"
          }
        ],
        "responses": {
          "200": {
            "description": "The requeued delivery, in the same shape as one GET /api/v1/webhooks/{id}/deliveries row.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "webhook_delivery"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookDelivery"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Dead-lettered delivery requeued",
                    "value": {
                      "object": "webhook_delivery",
                      "data": {
                        "id": 456,
                        "object": "webhook_delivery",
                        "event_id": "evt_whale_trades_inserted_1700000000_3",
                        "event_type": "whale_trades_inserted",
                        "status": "pending",
                        "attempt_count": 0,
                        "last_response_status": 503,
                        "last_error": "non-2xx response",
                        "next_attempt_at": "2026-06-04T12:00:00Z",
                        "retry_schedule_reason": "manual_redelivery",
                        "created_at": "2026-06-04T09:00:00Z"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "The webhook endpoint is not owned by the caller or was deleted, or the delivery does not belong to that endpoint or was removed by retention.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "The delivery cannot be requeued in its current state. error.param is delivery_id when the delivery itself is the cause (already delivered, or still queued) and endpoint when the endpoint would not receive it (disabled, not verified, or no longer subscribed to its event_type); error.message names the fix. error.reason is idempotency_in_progress while the same keyed request is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "idempotency_in_progress": {
                    "summary": "Idempotent mutation still in progress",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "bad_request",
                        "message": "Your previous request is still processing. Retry in a moment.",
                        "param": "Idempotency-Key",
                        "reason": "idempotency_in_progress"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  },
                  "already_delivered": {
                    "summary": "The delivery already succeeded",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "bad_request",
                        "message": "This webhook delivery was already delivered. Only a dead_letter delivery can be redelivered.",
                        "param": "delivery_id"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  },
                  "already_queued": {
                    "summary": "The delivery is still queued",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "bad_request",
                        "message": "This webhook delivery is already queued with status retry, so the worker attempts it without a redelivery. Only a dead_letter delivery can be redelivered.",
                        "param": "delivery_id"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  },
                  "endpoint_disabled": {
                    "summary": "The endpoint is disabled",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "bad_request",
                        "message": "Webhook endpoint 123 is disabled, so a redelivered delivery would be dead-lettered again. Re-enable it with PATCH /api/v1/webhooks/123 {\"enabled\": true}, then retry this request.",
                        "param": "endpoint"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The Idempotency-Key was already used with a different request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "different_body": {
                    "summary": "Idempotency key reused with a different body",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "bad_request",
                        "message": "Idempotency-Key already used with a different request body",
                        "param": "Idempotency-Key"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -X POST \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  -H 'Idempotency-Key: wh_redeliver_456' \\\n  'https://api.0xinsider.com/api/v1/webhooks/123/deliveries/456/redeliver'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "webhook_delivery",
            "data": {
              "id": 456,
              "object": "webhook_delivery",
              "event_id": "evt_whale_trades_inserted_1700000000_3",
              "event_type": "whale_trades_inserted",
              "status": "pending",
              "attempt_count": 0,
              "last_response_status": 503,
              "last_error": "non-2xx response",
              "next_attempt_at": "2026-06-04T12:00:00Z",
              "retry_schedule_reason": "manual_redelivery",
              "created_at": "2026-06-04T09:00:00Z"
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["webhooks"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/webhooks/{id}": {
      "get": {
        "operationId": "getWebhook",
        "summary": "Get one builder webhook destination",
        "description": "Returns one webhook destination owned by the authenticated API key user.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhook endpoint id owned by the authenticated API key user.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook destination",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "webhook"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookEndpoint"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Endpoint pending verification",
                    "value": {
                      "object": "webhook",
                      "data": {
                        "id": 1,
                        "object": "webhook",
                        "name": "Production webhook",
                        "url": "https://example.com/0xinsider/webhook",
                        "event_types": ["whale_trades_inserted"],
                        "trade_filters": {},
                        "price_move_filters": null,
                        "status": "pending_verification",
                        "verified_at": null,
                        "verification_token_expires_at": "2026-09-23T03:14:44.903437Z",
                        "failure_count": 0,
                        "created_at": "2026-09-22T03:14:42.182366Z",
                        "updated_at": "2026-09-22T03:14:42.182366Z",
                        "retry_policy": {
                          "max_attempts": 8,
                          "terminal_status": "dead_letter",
                          "retry_horizon_seconds": 7380,
                          "disable_after_consecutive_failures": 8
                        },
                        "secret_rotation": {
                          "status": "idle",
                          "overlap_expires_at": null
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/webhooks/{id}'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "webhook",
            "data": {
              "id": 1,
              "object": "webhook",
              "name": "Production webhook",
              "url": "https://example.com/0xinsider/webhook",
              "event_types": ["whale_trades_inserted"],
              "status": "pending_verification"
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["webhooks"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      },
      "patch": {
        "operationId": "updateWebhook",
        "summary": "Update a builder webhook destination",
        "description": "Updates name, HTTPS URL, event types, or enabled state. URL changes force pending_verification and return a new verification token; the new destination must answer 2xx to the signed webhook.verification challenge before deliveries resume. A URL change returns 409 with error.reason=webhook_delivery_in_progress while this destination has an active delivery; retry the same mutation after that request completes.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhook endpoint id owned by the authenticated API key user.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional safe-retry key. Reuse the same value only when retrying the exact same mutation request body; a different body returns 422 and an in-flight matching request returns 409.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255
            },
            "example": "wh_idem_01HX7Y9ZQ4K7Z0Q2E4N6A8C1BF"
          }
        ],
        "requestBody": {
          "description": "Webhook fields to replace or preserve.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookRequest"
              },
              "example": {
                "name": "Updated webhook",
                "enabled": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook destination",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "webhook"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookEndpoint"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Endpoint renamed and paused",
                    "value": {
                      "data": {
                        "created_at": "2026-09-22T03:14:42.182366Z",
                        "event_types": ["whale_trades_inserted"],
                        "trade_filters": {},
                        "price_move_filters": null,
                        "failure_count": 0,
                        "id": 1,
                        "name": "Production webhook (paused)",
                        "object": "webhook",
                        "retry_policy": {
                          "disable_after_consecutive_failures": 8,
                          "max_attempts": 8,
                          "retry_horizon_seconds": 7380,
                          "terminal_status": "dead_letter"
                        },
                        "secret_rotation": {
                          "status": "idle",
                          "overlap_expires_at": null
                        },
                        "status": "disabled",
                        "updated_at": "2026-09-22T03:14:46.963773Z",
                        "url": "https://example.com/0xinsider/webhook",
                        "verification_token_expires_at": "2026-09-23T03:14:44.903437Z",
                        "verified_at": null
                      },
                      "meta": {
                        "cached": false,
                        "cost": 1,
                        "request_id": "req_example"
                      },
                      "object": "webhook"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "The request body is over 1048576 bytes. error.code is bad_request, error.reason is payload_too_large and error.param is body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "415": {
            "description": "The body was not sent as Content-Type: application/json. error.code is bad_request, error.reason is unsupported_media_type and error.param is content-type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "The same idempotent mutation is still running, or this destination has an active delivery whose frozen URL cannot change until its request completes. Branch on error.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "idempotency_in_progress": {
                    "summary": "Idempotent mutation still in progress",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "bad_request",
                        "message": "Your previous request is still processing. Retry in a moment.",
                        "param": "Idempotency-Key",
                        "reason": "idempotency_in_progress"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  },
                  "delivery_in_progress": {
                    "summary": "Destination URL is frozen for an active delivery",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "bad_request",
                        "message": "webhook URL cannot change while a delivery is processing; retry after the active request completes",
                        "param": "endpoint",
                        "reason": "webhook_delivery_in_progress"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The Idempotency-Key was already used with a different request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "different_body": {
                    "summary": "Idempotency key reused with a different body",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "bad_request",
                        "message": "Idempotency-Key already used with a different request body",
                        "param": "Idempotency-Key"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -X PATCH \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"name\":\"Updated webhook\",\"enabled\":true}' \\\n  'https://api.0xinsider.com/api/v1/webhooks/{id}'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "webhook",
            "data": {
              "id": 1,
              "object": "webhook",
              "name": "Production webhook",
              "url": "https://example.com/0xinsider/webhook",
              "event_types": ["whale_trades_inserted"],
              "status": "pending_verification"
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["webhooks"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      },
      "delete": {
        "operationId": "deleteWebhook",
        "summary": "Disable a builder webhook destination",
        "description": "Soft-deletes a webhook destination owned by the authenticated API key user. Existing delivery audit rows remain retained.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhook endpoint id owned by the authenticated API key user.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional safe-retry key. Reuse the same value only when retrying the exact same mutation request body; a different body returns 422 and an in-flight matching request returns 409.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255
            },
            "example": "wh_idem_01HX7Y9ZQ4K7Z0Q2E4N6A8C1BF"
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook destination",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "webhook"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookEndpoint"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Endpoint removed",
                    "value": {
                      "data": {
                        "created_at": "2026-09-22T03:14:42.182366Z",
                        "event_types": ["whale_trades_inserted"],
                        "trade_filters": {},
                        "price_move_filters": null,
                        "failure_count": 0,
                        "id": 1,
                        "name": "Production webhook (paused)",
                        "object": "webhook",
                        "retry_policy": {
                          "disable_after_consecutive_failures": 8,
                          "max_attempts": 8,
                          "retry_horizon_seconds": 7380,
                          "terminal_status": "dead_letter"
                        },
                        "secret_rotation": {
                          "status": "idle",
                          "overlap_expires_at": null
                        },
                        "status": "disabled",
                        "updated_at": "2026-09-22T03:14:50.329178Z",
                        "url": "https://example.com/0xinsider/webhook",
                        "verification_token_expires_at": "2026-09-23T03:14:44.903437Z",
                        "verified_at": null
                      },
                      "meta": {
                        "cached": false,
                        "cost": 1,
                        "request_id": "req_example"
                      },
                      "object": "webhook"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "An Idempotency-Key request with the same body is still in progress. Retry shortly with the same key and body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "in_progress": {
                    "summary": "Idempotency request still in progress",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "bad_request",
                        "message": "Your previous request is still processing. Retry in a moment.",
                        "param": "Idempotency-Key",
                        "reason": "idempotency_in_progress"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The Idempotency-Key was already used with a different request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "different_body": {
                    "summary": "Idempotency key reused with a different body",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "bad_request",
                        "message": "Idempotency-Key already used with a different request body",
                        "param": "Idempotency-Key"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -X DELETE \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/webhooks/{id}'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "webhook",
            "data": {
              "id": 1,
              "object": "webhook",
              "name": "Production webhook",
              "url": "https://example.com/0xinsider/webhook",
              "event_types": ["whale_trades_inserted"],
              "status": "pending_verification"
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["webhooks"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/webhooks/{id}/verify": {
      "post": {
        "operationId": "verifyWebhook",
        "summary": "Verify a builder webhook destination",
        "description": "Activates a pending webhook destination. Two conditions must both hold: the one-time verification token matches and has not expired, AND the destination answers 2xx to a signed challenge this operation POSTs to the endpoint's stored url. The challenge body is {\"type\":\"webhook.verification\",\"token\":\"<verification_token>\",\"webhook_id\":<id>}. It carries x-0xinsider-event-type: webhook.verification plus the same x-0xinsider-timestamp and x-0xinsider-signature headers a delivery carries, signed with that endpoint's signing_secret, so verify it exactly as you verify a delivery. Answer any 2xx within 10 seconds; the challenge response body is never read, and the challenge follows no redirects. A status outside 2xx, no answer within 10 seconds, or a url that does not resolve to a publicly routable address leaves status at pending_verification and returns 422. The token alone never activates an endpoint.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhook endpoint id owned by the authenticated API key user.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "description": "One-time verification token for the pending webhook.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyWebhookRequest"
              },
              "example": {
                "verification_token": "whv_example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook destination",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "webhook"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookEndpoint"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Challenge answered; the endpoint is active",
                    "value": {
                      "object": "webhook",
                      "data": {
                        "id": 1,
                        "object": "webhook",
                        "name": "Production webhook",
                        "url": "https://example.com/0xinsider/webhook",
                        "event_types": ["whale_trades_inserted"],
                        "trade_filters": {},
                        "price_move_filters": null,
                        "status": "active",
                        "verified_at": "2026-09-22T03:16:02.417210Z",
                        "verification_token_expires_at": "2026-09-23T03:14:44.903437Z",
                        "failure_count": 0,
                        "created_at": "2026-09-22T03:14:42.182366Z",
                        "updated_at": "2026-09-22T03:16:02.417210Z",
                        "retry_policy": {
                          "max_attempts": 8,
                          "terminal_status": "dead_letter",
                          "retry_horizon_seconds": 7380,
                          "disable_after_consecutive_failures": 8
                        },
                        "secret_rotation": {
                          "status": "idle",
                          "overlap_expires_at": null
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "The request body is over 1048576 bytes. error.code is bad_request, error.reason is payload_too_large and error.param is body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "415": {
            "description": "The body was not sent as Content-Type: application/json. error.code is bad_request, error.reason is unsupported_media_type and error.param is content-type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "422": {
            "description": "The destination did not pass the verification challenge, so status stays pending_verification and no event is ever delivered to it. error.code is bad_request and error.param is url; error.message names which outcome occurred: the destination answered a status outside 2xx, it did not answer within the 10-second challenge budget, or its url did not resolve to a publicly routable address. The destination's response body and its resolved address are never echoed. Retry with the same token once the destination answers the challenge.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -X POST \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"verification_token\":\"whv_example\"}' \\\n  'https://api.0xinsider.com/api/v1/webhooks/{id}/verify'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "webhooks",
            "data": {},
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["webhooks"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/webhooks/{id}/rotate-secret/prepare": {
      "post": {
        "operationId": "prepareWebhookSecret",
        "summary": "Prepare a staged builder webhook signing secret",
        "description": "Creates a pending signing secret while the current secret remains active. Deploy the returned one-time signing_secret to the receiver before calling activate. The response exposes secret_rotation.status=pending; an existing pending secret is returned again so a lost response can be recovered safely.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhook endpoint id owned by the authenticated API key user.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional safe-retry key. Reuse the same value only when retrying the exact same mutation request body; a different body returns 422 and an in-flight matching request returns 409.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255
            },
            "example": "wh_idem_01HX7Y9ZQ4K7Z0Q2E4N6A8C1BF"
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook destination with the prepared signing secret",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "webhook"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookEndpoint"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Webhook endpoint not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The request timed out; reuse the same Idempotency-Key to learn whether it completed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "The previous signing secret is still in its bounded overlap window; retire it before preparing another staged secret. A keyed request can also return idempotency_in_progress while the same request is running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "422": {
            "description": "The Idempotency-Key was already used with a different request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n+  -X POST \\\n+  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n+  -H 'Content-Type: application/json' \\\n+  -d '{}' \\\n+  'https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret/prepare'"
          }
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["webhooks"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/webhooks/{id}/rotate-secret/activate": {
      "post": {
        "operationId": "activateWebhookSecret",
        "summary": "Activate a staged builder webhook signing secret",
        "description": "Promotes the prepared signing secret to current, returns it once, and signs every delivery with both the new and previous secrets for one hour. Call retire after the receiver has completed its rollout. The current secret remains available through the existing immediate rotate-secret route for emergency replacement.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhook endpoint id owned by the authenticated API key user.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional safe-retry key. Reuse the same value only when retrying the exact same mutation request body; a different body returns 422 and an in-flight matching request returns 409.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255
            },
            "example": "wh_idem_01HX7Y9ZQ4K7Z0Q2E4N6A8C1BF"
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook destination with the activated signing secret",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "webhook"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookEndpoint"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Webhook endpoint not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The request timed out; reuse the same Idempotency-Key to learn whether it completed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "No staged secret is prepared, or the previous signing secret is still in its bounded overlap window. A keyed request can also return idempotency_in_progress while the same request is running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "422": {
            "description": "The Idempotency-Key was already used with a different request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n+  -X POST \\\n+  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n+  -H 'Content-Type: application/json' \\\n+  -d '{}' \\\n+  'https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret/activate'"
          }
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["webhooks"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/webhooks/{id}/rotate-secret/retire": {
      "post": {
        "operationId": "retireWebhookSecret",
        "summary": "Retire the previous builder webhook signing secret",
        "description": "Ends the one-hour dual-signature overlap and removes the previous signing secret from future delivery authorization. Call this after the receiver accepts the activated secret. The operation is idempotent and does not return signing_secret.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhook endpoint id owned by the authenticated API key user.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional safe-retry key. Reuse the same value only when retrying the exact same mutation request body; a different body returns 422 and an in-flight matching request returns 409.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255
            },
            "example": "wh_idem_01HX7Y9ZQ4K7Z0Q2E4N6A8C1BF"
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook destination after the previous signing secret is retired",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "webhook"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookEndpoint"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Webhook endpoint not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The request timed out; reuse the same Idempotency-Key to learn whether it completed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "A keyed request with the same body is still in progress; retry with the same key and body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "422": {
            "description": "The Idempotency-Key was already used with a different request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n+  -X POST \\\n+  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n+  -H 'Content-Type: application/json' \\\n+  -d '{}' \\\n+  'https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret/retire'"
          }
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["webhooks"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/webhooks/{id}/rotate-secret": {
      "post": {
        "operationId": "rotateWebhookSecret",
        "summary": "Rotate a builder webhook signing secret",
        "description": "Rotates the endpoint signing secret and returns the new signing_secret once in the response. Returns 409 with error.reason=webhook_delivery_in_progress while a live delivery freezes the current signing nonce; retry after it completes.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhook endpoint id owned by the authenticated API key user.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional safe-retry key. Reuse the same value only when retrying the exact same mutation request body; a different body returns 422 and an in-flight matching request returns 409.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255
            },
            "example": "wh_idem_01HX7Y9ZQ4K7Z0Q2E4N6A8C1BF"
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook destination",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "webhook"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookEndpoint"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Secret rotated",
                    "value": {
                      "data": {
                        "created_at": "2026-09-22T03:14:42.182366Z",
                        "event_types": ["whale_trades_inserted"],
                        "trade_filters": {},
                        "price_move_filters": null,
                        "failure_count": 0,
                        "id": 1,
                        "name": "Production webhook (paused)",
                        "object": "webhook",
                        "retry_policy": {
                          "disable_after_consecutive_failures": 8,
                          "max_attempts": 8,
                          "retry_horizon_seconds": 7380,
                          "terminal_status": "dead_letter"
                        },
                        "secret_rotation": {
                          "status": "idle",
                          "overlap_expires_at": null
                        },
                        "signing_secret": "whsec_4fcoxLTiUpNuOpeWeJJNUS6epNeLDwa_AGHHPptlrq0",
                        "status": "disabled",
                        "updated_at": "2026-09-22T03:14:48.156303Z",
                        "url": "https://example.com/0xinsider/webhook",
                        "verification_token_expires_at": "2026-09-23T03:14:44.903437Z",
                        "verified_at": null
                      },
                      "meta": {
                        "cached": false,
                        "cost": 1,
                        "request_id": "req_example"
                      },
                      "object": "webhook"
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "The same idempotent mutation is still running, or this destination has an active delivery whose signing secret cannot rotate until its request completes. Branch on error.reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "idempotency_in_progress": {
                    "summary": "Idempotent mutation still in progress",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "bad_request",
                        "message": "Your previous request is still processing. Retry in a moment.",
                        "param": "Idempotency-Key",
                        "reason": "idempotency_in_progress"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  },
                  "delivery_in_progress": {
                    "summary": "Destination signing secret is frozen for an active delivery",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "bad_request",
                        "message": "webhook signing secret cannot rotate while a delivery is processing; retry after the active request completes",
                        "param": "endpoint",
                        "reason": "webhook_delivery_in_progress"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "The Idempotency-Key was already used with a different request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "different_body": {
                    "summary": "Idempotency key reused with a different body",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "bad_request",
                        "message": "Idempotency-Key already used with a different request body",
                        "param": "Idempotency-Key"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -X POST \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{}' \\\n  'https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "webhook",
            "data": {
              "id": 1,
              "object": "webhook",
              "name": "Production webhook",
              "url": "https://example.com/0xinsider/webhook",
              "event_types": ["whale_trades_inserted"],
              "status": "pending_verification"
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["webhooks"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Health check",
        "description": "Returns API health status. No authentication required. Limited to 120 requests per minute per IP.",
        "tags": ["System"],
        "security": [],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Health status",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Stable validator for the current health payload. Re-send it via If-None-Match for conditional GETs.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "health"
                    },
                    "data": {
                      "type": "object",
                      "required": ["status", "db", "cache", "subsystems"],
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": ["ok", "degraded", "down", "maintenance"]
                        },
                        "db": {
                          "type": "boolean"
                        },
                        "cache": {
                          "type": "boolean"
                        },
                        "subsystems": {
                          "type": "object",
                          "required": ["background_jobs", "webhook_compatibility"],
                          "properties": {
                            "webhook_compatibility": {
                              "type": "boolean",
                              "description": "Whether the webhook outbox schema validated on this probe. false lowers status to degraded. true during a maintenance window, when nothing is probed."
                            },
                            "background_jobs": {
                              "type": "object",
                              "required": [
                                "status",
                                "checked",
                                "total",
                                "healthy",
                                "stale",
                                "missing",
                                "invalid",
                                "unconfigured",
                                "paused"
                              ],
                              "description": "Public-safe aggregate status for expected background job successful-completion heartbeats. Does not expose Redis keys, job names, raw errors, provider payloads, wallet addresses, or condition IDs.",
                              "properties": {
                                "status": {
                                  "type": "string",
                                  "enum": ["ok", "degraded", "down", "not_checked"]
                                },
                                "checked": {
                                  "type": "boolean"
                                },
                                "total": {
                                  "type": "integer",
                                  "minimum": 0
                                },
                                "healthy": {
                                  "type": "integer",
                                  "minimum": 0
                                },
                                "stale": {
                                  "type": "integer",
                                  "minimum": 0
                                },
                                "missing": {
                                  "type": "integer",
                                  "minimum": 0
                                },
                                "invalid": {
                                  "type": "integer",
                                  "minimum": 0
                                },
                                "unconfigured": {
                                  "type": "integer",
                                  "minimum": 0
                                },
                                "paused": {
                                  "type": "integer",
                                  "minimum": 0,
                                  "description": "Heavy-periodic jobs that are stale/missing/invalid while the heavy executor is disabled (heavy_pipeline_control.executor_mode != 'active'), so this binary does not dispatch them. Observable but expected; they never drive status to 'down' (paused > 0 yields 'degraded')."
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "health",
                      "data": {
                        "status": "ok",
                        "db": true,
                        "cache": true,
                        "subsystems": {
                          "background_jobs": {
                            "status": "ok",
                            "checked": true,
                            "total": 33,
                            "healthy": 33,
                            "stale": 0,
                            "missing": 0,
                            "invalid": 0,
                            "unconfigured": 0,
                            "paused": 0
                          },
                          "webhook_compatibility": true
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current health payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged health payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/health'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "health",
            "data": {
              "status": "ok"
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/mcp": {
      "post": {
        "operationId": "createMcpJsonRpcResponse",
        "summary": "Remote MCP endpoint (JSON-RPC)",
        "description": "Model Context Protocol (MCP) Streamable HTTP transport. Accepts one JSON-RPC 2.0 request or notification. ID-bearing initialize, ping, tools/list, and tools/call requests (and server/discover on revision 2026-07-28) receive one same-ID JSON-RPC response; an unknown method, or a notification method sent with an id, answers JSON-RPC error -32601. Every ID-less message (a notification, known or not) receives HTTP 202 with no body and runs nothing; an unsolicited response message receives HTTP 400 with a JSON-RPC -32600 body and no id. Unknown cancellation IDs are ignored; cancellation does not stop running tool work. Only tools/call is counted against the per-minute request budget, the monthly quota and pay-as-you-go usage; every other message, with or without a key, spends none of them and reports the per-IP budget in RateLimit-* (since 2026-10-18). Remote MCP exposes 72 tools for public V1 read operations: get_leaderboard, get_trader, batch_get_traders, get_large_trades, get_large_trade, get_large_trades_history, get_whale_trades, get_whale_trade, get_whale_trades_history, get_edge_hunter, list_games, get_game, list_game_markets, list_props, get_game_sharp_money, get_game_trades, get_game_holders, get_market_flow, batch_get_market_flow, get_market_intel, batch_get_market_intel, get_sharp_money_flows, get_smart_money_flows, get_market_snapshot, get_suspicious_trades, get_suspicious_trade, get_insider_radar, get_insider_radar_flag, get_positions, get_position_timeline, get_position_timeline_by_id, search_markets, search_content, explore_markets, get_event_replay_since, list_webhooks, get_webhook, get_daily_report_snapshot, get_weekly_report_snapshot, get_monthly_report_snapshot, get_resolution_report, get_report, get_trader_export_snapshot, get_coverage, get_platforms, get_usage, get_account, get_large_positions, get_trending_wallets, get_leaderboard_leagues, get_sport_leaderboard, list_category_leaders, get_category_leaderboard, get_trader_pnl, get_pick_of_the_day, get_pick_of_the_day_ledger_entry, get_pick_of_the_day_archive, get_pick_of_the_day_stats, get_trader_context, get_trader_categories, get_trader_grade_at, get_trader_clv, get_market_holders, get_market_top_holders, get_market_candles, get_market_close, get_market_wallets_in_out, get_combo_fills, get_combos_summary, get_combo, get_large_trade_counterparty_executions, get_large_trade_counterparty_makers. Webhook create/update/delete/verify/rotate operations are intentionally not exposed as remote MCP tools. The remote endpoint advertises tools only; it does not implement resources/list, resources/read, prompts/list, or prompts/get. Each tool dispatches to the matching /api/v1/* handler in-process so auth, rate limits, and payload shape match. initialize, notifications/initialized, ping and tools/list answer without a credential; tools/call (and any GET) need Authorization: Bearer <token> with an OAuth 2.1 access token (see the oauth2 security scheme; a tool outside the token's scopes returns isError) or an API key, and without one answer HTTP 401 with a WWW-Authenticate challenge whose resource_metadata names the RFC 9728 document at /.well-known/oauth-protected-resource/api/v1/mcp. A key in a ?token= query parameter is rejected on every authenticated route (the public routes ignore it) with 401 invalid_api_key and error.reason api_key_in_query, because URLs land in shell history, browser history, and logs; a client that can only take a URL can run the @0xinsider/mcp stdio package. The endpoint is stateless: it mints no Mcp-Session-Id and ignores one a client sends. Origin header, when present, is validated against the 0xinsider + localhost allowlist. tools/call arguments are validated against the tool's advertised inputSchema before anything runs: an unknown key, a wrong type, an out-of-range number, a value outside an enum or an argument combination outside a oneOf answers a tool result with isError true whose text names the field, never a query built from the arguments that fit; a tools/call without name, or whose arguments is not an object, answers JSON-RPC error -32602 and runs nothing. Every tools/call result carries the REST envelope's meta verbatim (request_id, cached, cache_age_s, cost, and the route's provenance such as source and completeness on get_whale_trades_history or ranking_source and directional_source on get_edge_hunter) as structuredContent.meta beside the payload's own keys, and a tool failure carries structuredContent.error with the REST error fields verbatim (code, reason, param, doc_url, retry_at) plus retry_after_seconds, request_id and status, beside its text. The MCP-Protocol-Version request header is checked on every POST: a value outside 2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05 answers HTTP 400 with the standard error envelope (error.code bad_request); an absent header is served as 2025-03-26, the transport specification's compatibility default. Revision 2026-07-28 also requires the Mcp-Method header (JSON-RPC error -32020 without it) and adds resultType to every result. Browser preflight allows MCP-Protocol-Version, Mcp-Method and Mcp-Name.",
        "tags": ["MCP"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "description": "The negotiated MCP protocol revision, sent on every request after initialize (MCP Streamable HTTP transport). Accepted values: 2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05. Any other value answers HTTP 400 with the standard error envelope (error.code bad_request), unless the request names its revision in params._meta. Absent, the request is served as 2025-03-26.",
            "schema": {
              "type": "string",
              "enum": ["2026-07-28", "2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05"]
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "description": "The JSON-RPC method of the body. Required on revision 2026-07-28, which answers JSON-RPC error -32020 without it; earlier revisions ignore it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "description": "The tool name of a tools/call on revision 2026-07-28; it must match params.name.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "MCP JSON-RPC 2.0 request or notification envelope. Omit id for supported notifications.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["jsonrpc", "method"],
                "properties": {
                  "jsonrpc": {
                    "type": "string",
                    "description": "JSON-RPC protocol version; this server accepts 2.0.",
                    "const": "2.0"
                  },
                  "id": {
                    "description": "Request identifier, a string or a number, echoed exactly in one JSON-RPC response; a notification omits it and receives an empty HTTP 202. A null id answers HTTP 400 with JSON-RPC error -32600.",
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "number"
                      }
                    ]
                  },
                  "method": {
                    "type": "string",
                    "description": "MCP method to invoke.",
                    "enum": [
                      "initialize",
                      "notifications/initialized",
                      "notifications/cancelled",
                      "ping",
                      "tools/list",
                      "tools/call",
                      "server/discover"
                    ]
                  },
                  "params": {
                    "type": "object",
                    "description": "Method-specific MCP parameters."
                  }
                }
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["jsonrpc", "id"],
                  "properties": {
                    "jsonrpc": {
                      "type": "string",
                      "const": "2.0"
                    },
                    "id": {
                      "oneOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "number"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "result": {
                      "type": "object"
                    },
                    "error": {
                      "type": "object",
                      "required": ["code", "message"],
                      "properties": {
                        "code": {
                          "type": "integer"
                        },
                        "message": {
                          "type": "string"
                        },
                        "data": {
                          "description": "Optional JSON-serializable error data.",
                          "oneOf": [
                            {
                              "type": "object"
                            },
                            {
                              "type": "array"
                            },
                            {
                              "type": "string"
                            },
                            {
                              "type": "number"
                            },
                            {
                              "type": "boolean"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "jsonrpc": "2.0",
                      "id": 1,
                      "result": {
                        "tools": [
                          {
                            "_meta": {
                              "com.oxinsider/docs-group": "traders"
                            },
                            "annotations": {
                              "destructiveHint": false,
                              "idempotentHint": true,
                              "openWorldHint": false,
                              "readOnlyHint": true,
                              "title": "Get Trader Leaderboard"
                            },
                            "description": "Get the top-ranked prediction market traders (grades S, A, B only). Sorted by composite score descending. Supports cursor pagination and optional filters.\n\nArgs:\n  - limit (number, 1-100, default 20): Max results per page\n  - cursor (string, optional): Pagination cursor from previous response\n  - category (string, optional): Filter by category slug\n  - strategy (string, optional): Filter by strategy type\n\nReturns: Ranked list of traders with grade, score, P&L, volume, win rate, and strategy.",
                            "inputSchema": {
                              "additionalProperties": false,
                              "properties": {
                                "category": {
                                  "description": "Filter by category slug",
                                  "type": "string"
                                },
                                "cursor": {
                                  "description": "Pagination cursor from previous response",
                                  "type": "string"
                                },
                                "limit": {
                                  "default": 20,
                                  "description": "Max results (1-100, default 20)",
                                  "maximum": 100,
                                  "minimum": 1,
                                  "type": "integer"
                                },
                                "strategy": {
                                  "description": "Filter by strategy type",
                                  "type": "string"
                                }
                              },
                              "type": "object"
                            },
                            "name": "get_leaderboard",
                            "title": "Get Trader Leaderboard"
                          },
                          {
                            "_meta": {
                              "com.oxinsider/docs-group": "traders"
                            },
                            "annotations": {
                              "destructiveHint": false,
                              "idempotentHint": true,
                              "openWorldHint": false,
                              "readOnlyHint": true,
                              "title": "Get trader"
                            },
                            "description": "Look up a prediction market trader by wallet address or username. Returns grade (S through F), P&L breakdown, win rate, and volume.\n\nOptional expand fields for heavier data:\n- strategy: Trading strategy classification\n- categories: Per-category performance breakdown\n- quant_metrics: retired since 2026-10-27; accepted and never returned, because its metrics covered every market of the wallet. Read pnl.in_scope or get_trader_pnl for the sports and esports record\n- trust: Per-field provenance (source, freshness, reconciliation, completeness) for grade, P&L, and stats\n\nA wallet address with no trader yet returns sync_status \"unknown\" (not an error). A username or trader id that matches no trader is a not_found error.\n\nArgs:\n  - address (string, required): Ethereum wallet address (0x...) or trader username\n  - expand (string[], optional): Heavy fields to include: \"strategy\", \"categories\", \"trust\" (\"quant_metrics\" is accepted and returns nothing)\n\nReturns: Trader profile with grade, P&L, stats, and optional expanded fields.",
                            "inputSchema": {
                              "additionalProperties": false,
                              "properties": {
                                "address": {
                                  "description": "Ethereum wallet address (0x...) or trader username",
                                  "maxLength": 100,
                                  "minLength": 1,
                                  "type": "string"
                                },
                                "expand": {
                                  "description": "Optional heavy fields to include",
                                  "items": {
                                    "enum": ["strategy", "categories"],
                                    "type": "string"
                                  },
                                  "type": "array"
                                }
                              },
                              "required": ["address"],
                              "type": "object"
                            },
                            "name": "get_trader",
                            "title": "Get trader"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "202": {
            "description": "Supported ID-less ping, initialized, or cancellation notification accepted (no body). Unknown cancellation IDs are ignored, not executed.",
            "x-empty-body": true,
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "JSON-RPC parse (-32700) or invalid-request (-32600) error, an unsolicited response message (-32600, no id), or a header the transport refuses: an unsupported MCP-Protocol-Version answers the standard error envelope instead, and a missing Mcp-Method on revision 2026-07-28 answers -32020.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/McpJsonRpcError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Origin rejected or tier forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -X POST \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{}' \\\n  'https://api.0xinsider.com/api/v1/mcp'"
          }
        ],
        "x-examples": {
          "success": {
            "jsonrpc": "2.0",
            "id": 1,
            "result": {
              "protocolVersion": "2025-11-25"
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      },
      "get": {
        "operationId": "openMcpEventStream",
        "summary": "MCP GET: no server-to-client stream (405)",
        "description": "The MCP Streamable HTTP transport lets a client GET the endpoint to open a server-to-client text/event-stream, and lets the server answer 405 Method Not Allowed when it offers no such stream. This server sends no notifications, so an authenticated GET answers 405 with Allow: POST and the standard error envelope (error.reason method_not_allowed); a conforming client (the reference @modelcontextprotocol/sdk included) reads the 405 as no stream here and does not retry. Without a credential the GET answers 401 with the WWW-Authenticate challenge naming /.well-known/oauth-protected-resource/api/v1/mcp, which is where a client that has only run the public handshake learns to start the OAuth flow. Until 2026-09-22 an authenticated GET answered 200 text/event-stream and closed the body at once, which conforming clients reconnected to every second. Every JSON-RPC request goes over POST. Since 2026-10-18 the authenticated 405 spends no per-minute request, monthly quota or pay-as-you-go usage, and reports the per-IP budget in RateLimit-*.",
        "tags": ["MCP"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          }
        ],
        "responses": {
          "405": {
            "description": "No server-to-client stream is offered. Allow: POST names the one method the endpoint serves. Not a failure: send JSON-RPC requests with POST. The body is the standard error envelope with error.reason method_not_allowed (until 2026-10-31 a JSON-RPC error body with code -32004 and X-Mcp-Error-Code: -32004).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "example": {
                  "object": "error",
                  "error": {
                    "code": "bad_request",
                    "message": "GET is not served on /api/v1/mcp. The Allow header names the methods it accepts; GET /api/v1 lists every route.",
                    "doc_url": "https://docs.0xinsider.com/errors",
                    "reason": "method_not_allowed"
                  },
                  "meta": {
                    "request_id": "req_761340de9e5d",
                    "cached": false,
                    "cost": 1
                  }
                }
              }
            },
            "headers": {
              "Allow": {
                "description": "Always POST.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Origin rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS -D - -o /dev/null \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  -H 'Accept: text/event-stream' \\\n  'https://api.0xinsider.com/api/v1/mcp'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/reports": {
      "get": {
        "operationId": "getReports",
        "summary": "Unified report snapshot (granularity selector)",
        "description": "Unified convenience route (#4975) that consolidates the three singular report routes. Dispatches to the exact per-granularity cap (daily 50, weekly 100, monthly 200) and date window the legacy /api/v1/reports/{daily,weekly,monthly} routes use, so the response body is byte-identical to the matching legacy route for the same period. An ISO weekly period is a durable canonical snapshot; an explicit weekly from,to pair is an exact ephemeral range limited to 31 inclusive UTC days and never creates a persisted snapshot identity. A wider explicit range returns 400 invalid_query. The three legacy routes stay live. Also reachable via the MCP get_report selector.",
        "tags": ["Reports"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "granularity",
            "in": "query",
            "required": true,
            "description": "Report granularity selector.",
            "schema": {
              "type": "string",
              "enum": ["daily", "weekly", "monthly"]
            }
          },
          {
            "name": "period",
            "in": "query",
            "required": true,
            "description": "Period token for the granularity. daily: UTC date YYYY-MM-DD. weekly: ISO week YYYY-WW for a durable canonical snapshot, or a from,to YYYY-MM-DD pair for an exact ephemeral range limited to 31 inclusive UTC days. A wider explicit range returns 400 invalid_query. monthly: UTC month YYYY-MM. A period that ends before 2024-03-01, the first day report data covers, or starts after tomorrow UTC returns 400 bad_request with error.param=period.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Daily report snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "report_snapshot"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ReportSnapshot"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "report_snapshot",
                      "data": {
                        "kind": "daily",
                        "generated_at": "2026-09-19T05:08:19.809477+00:00",
                        "source_range": {
                          "start_date": "2026-09-18",
                          "end_date": "2026-09-18",
                          "timezone": "UTC"
                        },
                        "snapshot": {
                          "version": 11,
                          "storage": "durable",
                          "status": "final",
                          "generated_at": "2026-09-19T05:08:19.809477+00:00",
                          "mutable_until": null,
                          "period_closed": true,
                          "final_after": "2026-09-19T02:05:30Z",
                          "source_read_started_at": null
                        },
                        "completeness": {
                          "status": "complete",
                          "reason": "the requested source range is closed and this body was read after the whale-trade ingestion budget elapsed; zero-activity dates are represented by absence of whale rows",
                          "expected_days": 1,
                          "covered_days_with_large_trade_activity": 1,
                          "covered_days_with_whale_activity": 1
                        },
                        "reconciliation": {
                          "volume_kind": "local_whale_activity_volume",
                          "whale_volume_source": "whale_alerts.usdc_notional_num (provider usdcSize when supplied; size*price fallback when the WS/REST payload omits it, until reconciled, #5430)",
                          "notes": "Report whale volume is a source-range snapshot over local whale-alert activity, not provider lifetime trader volume."
                        },
                        "report": {
                          "market_scope": "all_markets",
                          "total_whale_trades": 21,
                          "total_large_trades": 21,
                          "total_whale_volume": 3023030.264827,
                          "total_large_trade_volume": 3023030.264827,
                          "biggest_trade_size": 666091.1616,
                          "active_traders": 13,
                          "top_whale_trades": [
                            {
                              "id": 84621,
                              "trade_time": "2026-09-18T18:50:02+00:00",
                              "side": "BUY",
                              "title": "Will Chelsea FC win on 2026-09-18?",
                              "outcome": "No",
                              "token_id": "78286428694124582556689109371207595630990062941257883403830956483521756500097",
                              "size": 666091.1616,
                              "price": 0.64,
                              "market_category": "Soccer",
                              "platform": "polymarket",
                              "name": "totoro3miyazaki",
                              "pseudonym": null,
                              "trader_grade": null
                            },
                            {
                              "id": 77339,
                              "trade_time": "2026-09-18T18:27:34+00:00",
                              "side": "BUY",
                              "title": "Will Chelsea FC win on 2026-09-18?",
                              "outcome": "No",
                              "token_id": "78286428694124582556689109371207595630990062941257883403830956483521756500097",
                              "size": 440760.7883,
                              "price": 0.639774,
                              "market_category": "Soccer",
                              "platform": "polymarket",
                              "name": "totoro3miyazaki",
                              "pseudonym": null,
                              "trader_grade": null
                            }
                          ],
                          "top_large_trades": [
                            {
                              "id": 84621,
                              "trade_time": "2026-09-18T18:50:02+00:00",
                              "side": "BUY",
                              "title": "Will Chelsea FC win on 2026-09-18?",
                              "outcome": "No",
                              "token_id": "78286428694124582556689109371207595630990062941257883403830956483521756500097",
                              "size": 666091.1616,
                              "price": 0.64,
                              "market_category": "Soccer",
                              "platform": "polymarket",
                              "name": "totoro3miyazaki",
                              "pseudonym": null,
                              "trader_grade": null
                            },
                            {
                              "id": 77339,
                              "trade_time": "2026-09-18T18:27:34+00:00",
                              "side": "BUY",
                              "title": "Will Chelsea FC win on 2026-09-18?",
                              "outcome": "No",
                              "token_id": "78286428694124582556689109371207595630990062941257883403830956483521756500097",
                              "size": 440760.7883,
                              "price": 0.639774,
                              "market_category": "Soccer",
                              "platform": "polymarket",
                              "name": "totoro3miyazaki",
                              "pseudonym": null,
                              "trader_grade": null
                            }
                          ],
                          "categories": [
                            {
                              "category": "Soccer",
                              "large_trade_count": 16,
                              "whale_trade_count": 16,
                              "category_volume": 2954574.525097
                            },
                            {
                              "category": "Esports",
                              "large_trade_count": 3,
                              "whale_trade_count": 3,
                              "category_volume": 45161.16613
                            }
                          ],
                          "grade_distribution": []
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter. A weekly explicit from/to range wider than 31 inclusive UTC days returns 400 with error.reason=invalid_query. A period that ends before 2024-03-01, the first day report data covers, or starts after tomorrow UTC returns 400 bad_request with error.param=period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. A weekly explicit range can return error.reason=read_model_warming when bounded custom-range admission is full and should be retried after Retry-After; the other 503 cause is the Redis-backed authenticated rate limiter outage cooldown.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/reports?granularity=daily&period=2026-02-17'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-mcp-tool": "get_report",
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/reports/daily": {
      "get": {
        "operationId": "getDailyReportSnapshot",
        "summary": "Daily report snapshot",
        "description": "Returns a dated daily whale-activity report snapshot with source_range, snapshot.status, completeness, and reconciliation metadata. Report whale volume is local whale-alert activity volume, not provider lifetime trader volume.",
        "tags": ["Reports"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "date",
            "in": "query",
            "required": true,
            "description": "UTC report date in YYYY-MM-DD format, from 2024-03-01 (the first day report data covers) through tomorrow UTC. Any other date returns 400 bad_request with error.param=date.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Daily report snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "report_snapshot"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ReportSnapshot"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "report_snapshot",
                      "data": {
                        "kind": "daily",
                        "generated_at": "2026-09-19T05:08:19.809477+00:00",
                        "source_range": {
                          "start_date": "2026-09-18",
                          "end_date": "2026-09-18",
                          "timezone": "UTC"
                        },
                        "snapshot": {
                          "version": 11,
                          "storage": "durable",
                          "status": "final",
                          "generated_at": "2026-09-19T05:08:19.809477+00:00",
                          "mutable_until": null,
                          "period_closed": true,
                          "final_after": "2026-09-19T02:05:30Z",
                          "source_read_started_at": null
                        },
                        "completeness": {
                          "status": "complete",
                          "reason": "the requested source range is closed and this body was read after the whale-trade ingestion budget elapsed; zero-activity dates are represented by absence of whale rows",
                          "expected_days": 1,
                          "covered_days_with_large_trade_activity": 1,
                          "covered_days_with_whale_activity": 1
                        },
                        "reconciliation": {
                          "volume_kind": "local_whale_activity_volume",
                          "whale_volume_source": "whale_alerts.usdc_notional_num (provider usdcSize when supplied; size*price fallback when the WS/REST payload omits it, until reconciled, #5430)",
                          "notes": "Report whale volume is a source-range snapshot over local whale-alert activity, not provider lifetime trader volume."
                        },
                        "report": {
                          "market_scope": "all_markets",
                          "total_whale_trades": 21,
                          "total_large_trades": 21,
                          "total_whale_volume": 3023030.264827,
                          "total_large_trade_volume": 3023030.264827,
                          "biggest_trade_size": 666091.1616,
                          "active_traders": 13,
                          "top_whale_trades": [
                            {
                              "id": 84621,
                              "trade_time": "2026-09-18T18:50:02+00:00",
                              "side": "BUY",
                              "title": "Will Chelsea FC win on 2026-09-18?",
                              "outcome": "No",
                              "token_id": "78286428694124582556689109371207595630990062941257883403830956483521756500097",
                              "size": 666091.1616,
                              "price": 0.64,
                              "market_category": "Soccer",
                              "platform": "polymarket",
                              "name": "totoro3miyazaki",
                              "pseudonym": null,
                              "trader_grade": null
                            },
                            {
                              "id": 77339,
                              "trade_time": "2026-09-18T18:27:34+00:00",
                              "side": "BUY",
                              "title": "Will Chelsea FC win on 2026-09-18?",
                              "outcome": "No",
                              "token_id": "78286428694124582556689109371207595630990062941257883403830956483521756500097",
                              "size": 440760.7883,
                              "price": 0.639774,
                              "market_category": "Soccer",
                              "platform": "polymarket",
                              "name": "totoro3miyazaki",
                              "pseudonym": null,
                              "trader_grade": null
                            }
                          ],
                          "top_large_trades": [
                            {
                              "id": 84621,
                              "trade_time": "2026-09-18T18:50:02+00:00",
                              "side": "BUY",
                              "title": "Will Chelsea FC win on 2026-09-18?",
                              "outcome": "No",
                              "token_id": "78286428694124582556689109371207595630990062941257883403830956483521756500097",
                              "size": 666091.1616,
                              "price": 0.64,
                              "market_category": "Soccer",
                              "platform": "polymarket",
                              "name": "totoro3miyazaki",
                              "pseudonym": null,
                              "trader_grade": null
                            },
                            {
                              "id": 77339,
                              "trade_time": "2026-09-18T18:27:34+00:00",
                              "side": "BUY",
                              "title": "Will Chelsea FC win on 2026-09-18?",
                              "outcome": "No",
                              "token_id": "78286428694124582556689109371207595630990062941257883403830956483521756500097",
                              "size": 440760.7883,
                              "price": 0.639774,
                              "market_category": "Soccer",
                              "platform": "polymarket",
                              "name": "totoro3miyazaki",
                              "pseudonym": null,
                              "trader_grade": null
                            }
                          ],
                          "categories": [
                            {
                              "category": "Soccer",
                              "large_trade_count": 16,
                              "whale_trade_count": 16,
                              "category_volume": 2954574.525097
                            },
                            {
                              "category": "Esports",
                              "large_trade_count": 3,
                              "whale_trade_count": 3,
                              "category_volume": 45161.16613
                            }
                          ],
                          "grade_distribution": []
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter. A date before 2024-03-01, the first day report data covers, or after tomorrow UTC returns 400 bad_request with error.param=date.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/reports/daily'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/reports/weekly": {
      "get": {
        "operationId": "getWeeklyReportSnapshot",
        "summary": "Weekly report snapshot",
        "description": "Returns a weekly whale-activity report snapshot. Pass an ISO YYYY-WW token for a durable canonical snapshot, or an exact from/to UTC range of at most 31 inclusive days for an ephemeral response. The response identifies closed ranges as final and current ranges as rolling.",
        "tags": ["Reports"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "UTC source-range start in YYYY-MM-DD format; required with to. Together with to, selects an exact ephemeral range of at most 31 inclusive UTC days. A start after tomorrow UTC returns 400 bad_request with error.param=from.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "UTC source-range end in YYYY-MM-DD format; required with from. Together with from, selects an exact ephemeral range of at most 31 inclusive UTC days. An end before 2024-03-01, the first day report data covers, returns 400 bad_request with error.param=to.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "week",
            "in": "query",
            "required": false,
            "description": "ISO week selector in YYYY-WW format; alternative to from/to. Selects a durable canonical snapshot. A week that ends before 2024-03-01, the first day report data covers, or starts after tomorrow UTC returns 400 bad_request with error.param=week.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Weekly report snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "report_snapshot"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ReportSnapshot"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "report_snapshot",
                      "data": {
                        "kind": "weekly",
                        "generated_at": "2026-09-21T11:45:11.573440+00:00",
                        "source_range": {
                          "start_date": "2026-09-07",
                          "end_date": "2026-09-13",
                          "timezone": "UTC"
                        },
                        "snapshot": {
                          "version": 41,
                          "storage": "durable",
                          "status": "final",
                          "generated_at": "2026-09-21T11:45:11.573440+00:00",
                          "mutable_until": null,
                          "period_closed": true,
                          "final_after": "2026-09-14T02:05:30Z",
                          "source_read_started_at": null
                        },
                        "completeness": {
                          "status": "complete",
                          "reason": "the requested source range is closed and this body was read after the whale-trade ingestion budget elapsed; zero-activity dates are represented by absence of whale rows",
                          "expected_days": 7,
                          "covered_days_with_large_trade_activity": 7,
                          "covered_days_with_whale_activity": 7
                        },
                        "reconciliation": {
                          "volume_kind": "local_whale_activity_volume",
                          "whale_volume_source": "whale_alerts.usdc_notional_num (provider usdcSize when supplied; size*price fallback when the WS/REST payload omits it, until reconciled, #5430)",
                          "notes": "Report whale volume is a source-range snapshot over local whale-alert activity, not provider lifetime trader volume."
                        },
                        "report": {
                          "market_scope": "all_markets",
                          "total_whale_trades": 370,
                          "total_large_trades": 370,
                          "total_whale_volume": 11017645.500849,
                          "total_large_trade_volume": 11017645.500849,
                          "biggest_trade_size": 491236.3567,
                          "active_traders": 153,
                          "top_whale_trades": [
                            {
                              "id": 12130,
                              "trade_time": "2026-09-09T23:21:04+00:00",
                              "side": "BUY",
                              "title": "US Open ATP: Alexander Zverev vs Botic van de Zandschulp",
                              "outcome": "Alexander Zverev",
                              "token_id": "9158437108174135547239483835198621883927847537872618727943792296109949759031",
                              "size": 491236.3567,
                              "price": 0.88,
                              "market_category": "Tennis",
                              "platform": "polymarket",
                              "name": "Noprajsk",
                              "pseudonym": null,
                              "trader_grade": null
                            },
                            {
                              "id": 12127,
                              "trade_time": "2026-09-09T23:19:42+00:00",
                              "side": "BUY",
                              "title": "US Open ATP: Alexander Zverev vs Botic van de Zandschulp",
                              "outcome": "Alexander Zverev",
                              "token_id": "9158437108174135547239483835198621883927847537872618727943792296109949759031",
                              "size": 378649.17296,
                              "price": 0.88,
                              "market_category": "Tennis",
                              "platform": "polymarket",
                              "name": "Noprajsk",
                              "pseudonym": null,
                              "trader_grade": null
                            }
                          ],
                          "top_large_trades": [
                            {
                              "id": 12130,
                              "trade_time": "2026-09-09T23:21:04+00:00",
                              "side": "BUY",
                              "title": "US Open ATP: Alexander Zverev vs Botic van de Zandschulp",
                              "outcome": "Alexander Zverev",
                              "token_id": "9158437108174135547239483835198621883927847537872618727943792296109949759031",
                              "size": 491236.3567,
                              "price": 0.88,
                              "market_category": "Tennis",
                              "platform": "polymarket",
                              "name": "Noprajsk",
                              "pseudonym": null,
                              "trader_grade": null
                            },
                            {
                              "id": 12127,
                              "trade_time": "2026-09-09T23:19:42+00:00",
                              "side": "BUY",
                              "title": "US Open ATP: Alexander Zverev vs Botic van de Zandschulp",
                              "outcome": "Alexander Zverev",
                              "token_id": "9158437108174135547239483835198621883927847537872618727943792296109949759031",
                              "size": 378649.17296,
                              "price": 0.88,
                              "market_category": "Tennis",
                              "platform": "polymarket",
                              "name": "Noprajsk",
                              "pseudonym": null,
                              "trader_grade": null
                            }
                          ],
                          "categories": [
                            {
                              "category": "Soccer",
                              "large_trade_count": 120,
                              "whale_trade_count": 120,
                              "category_volume": 3618430.255359
                            },
                            {
                              "category": "Tennis",
                              "large_trade_count": 65,
                              "whale_trade_count": 65,
                              "category_volume": 2751098.843941
                            }
                          ],
                          "grade_distribution": []
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter. A weekly explicit from/to range wider than 31 inclusive UTC days returns 400 with error.reason=invalid_query. A period that ends before 2024-03-01, the first day report data covers, returns 400 bad_request with error.param=week or to; one that starts after tomorrow UTC, with error.param=week or from.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. A weekly explicit range can return error.reason=read_model_warming when bounded custom-range admission is full and should be retried after Retry-After; the other 503 cause is the Redis-backed authenticated rate limiter outage cooldown.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/reports/weekly'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/reports/monthly": {
      "get": {
        "operationId": "getMonthlyReportSnapshot",
        "summary": "Monthly report snapshot",
        "description": "Returns a UTC monthly whale-activity report snapshot with source_range, completeness, and reconciliation metadata.",
        "tags": ["Reports"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "month",
            "in": "query",
            "required": true,
            "description": "UTC report month in YYYY-MM format. A month that ends before 2024-03-01, the first day report data covers, or starts after tomorrow UTC returns 400 bad_request with error.param=month.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Monthly report snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "report_snapshot"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ReportSnapshot"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "report_snapshot",
                      "data": {
                        "kind": "monthly",
                        "generated_at": "2026-09-21T11:35:11.849657+00:00",
                        "source_range": {
                          "start_date": "2026-08-01",
                          "end_date": "2026-08-31",
                          "timezone": "UTC"
                        },
                        "snapshot": {
                          "version": 34,
                          "storage": "durable",
                          "status": "final",
                          "generated_at": "2026-09-21T11:35:11.849657+00:00",
                          "mutable_until": null,
                          "period_closed": true,
                          "final_after": "2026-09-01T02:05:30Z",
                          "source_read_started_at": null
                        },
                        "completeness": {
                          "status": "complete",
                          "reason": "the requested source range is closed and this body was read after the whale-trade ingestion budget elapsed; zero-activity dates are represented by absence of whale rows",
                          "expected_days": 31,
                          "covered_days_with_large_trade_activity": 31,
                          "covered_days_with_whale_activity": 31
                        },
                        "reconciliation": {
                          "volume_kind": "local_whale_activity_volume",
                          "whale_volume_source": "whale_alerts.usdc_notional_num (provider usdcSize when supplied; size*price fallback when the WS/REST payload omits it, until reconciled, #5430)",
                          "notes": "Report whale volume is a source-range snapshot over local whale-alert activity, not provider lifetime trader volume."
                        },
                        "report": {
                          "market_scope": "all_markets",
                          "total_whale_trades": 310,
                          "total_large_trades": 310,
                          "total_whale_volume": 8941874.26362,
                          "total_large_trade_volume": 8941874.26362,
                          "biggest_trade_size": 599403.5518,
                          "active_traders": 119,
                          "top_whale_trades": [
                            {
                              "id": 52107,
                              "trade_time": "2026-08-24T07:49:48+00:00",
                              "side": "BUY",
                              "title": "Will Arsenal win the 2026-27 English Premier League?",
                              "outcome": "No",
                              "token_id": "51736214498022917360548120394716285037741962208815573690124478506613382910447",
                              "size": 599403.5518,
                              "price": 0.779956,
                              "market_category": "Soccer",
                              "platform": "polymarket",
                              "name": "VelvetNova27",
                              "pseudonym": null,
                              "trader_grade": null
                            },
                            {
                              "id": 52099,
                              "trade_time": "2026-08-05T07:41:45+00:00",
                              "side": "BUY",
                              "title": "Will Arsenal win the 2026-27 English Premier League?",
                              "outcome": "No",
                              "token_id": "51736214498022917360548120394716285037741962208815573690124478506613382910447",
                              "size": 372393.81953,
                              "price": 0.809366,
                              "market_category": "Soccer",
                              "platform": "polymarket",
                              "name": "blahblah344",
                              "pseudonym": null,
                              "trader_grade": null
                            }
                          ],
                          "top_large_trades": [
                            {
                              "id": 52107,
                              "trade_time": "2026-08-24T07:49:48+00:00",
                              "side": "BUY",
                              "title": "Will Arsenal win the 2026-27 English Premier League?",
                              "outcome": "No",
                              "token_id": "51736214498022917360548120394716285037741962208815573690124478506613382910447",
                              "size": 599403.5518,
                              "price": 0.779956,
                              "market_category": "Soccer",
                              "platform": "polymarket",
                              "name": "VelvetNova27",
                              "pseudonym": null,
                              "trader_grade": null
                            },
                            {
                              "id": 52099,
                              "trade_time": "2026-08-05T07:41:45+00:00",
                              "side": "BUY",
                              "title": "Will Arsenal win the 2026-27 English Premier League?",
                              "outcome": "No",
                              "token_id": "51736214498022917360548120394716285037741962208815573690124478506613382910447",
                              "size": 372393.81953,
                              "price": 0.809366,
                              "market_category": "Soccer",
                              "platform": "polymarket",
                              "name": "blahblah344",
                              "pseudonym": null,
                              "trader_grade": null
                            }
                          ],
                          "categories": [
                            {
                              "category": "Soccer",
                              "large_trade_count": 307,
                              "whale_trade_count": 307,
                              "category_volume": 8907186.7979
                            },
                            {
                              "category": "Tennis",
                              "large_trade_count": 3,
                              "whale_trade_count": 3,
                              "category_volume": 34687.46572
                            }
                          ],
                          "grade_distribution": []
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter. A month that ends before 2024-03-01, the first day report data covers, or starts after tomorrow UTC returns 400 bad_request with error.param=month.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/reports/monthly'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "list",
            "data": [],
            "has_more": false,
            "next_cursor": null,
            "total": 0,
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/reports/resolutions": {
      "get": {
        "operationId": "getResolutionReport",
        "summary": "Get the daily resolution report",
        "description": "One UTC day of resolved sports and esports markets: how often the side the profitable (S, A and B grade) wallets held won, beside how often every qualifying wallet's side won, one vote each. `markets` lists each market they held a position in, with the consensus side, its confidence, and the full roster of wallets, their side, cost and realized P&L; `view=totals` drops it. Counts cover the whole day before that list is filtered. A past day is served from its retained build: `generated_at` says when it was built and `source_updates_pending` that a newer build has been requested. 503 read_model_warming while the day has no build yet; one has been requested.",
        "tags": ["Reports"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "date",
            "in": "query",
            "required": true,
            "description": "UTC report date in YYYY-MM-DD format, no later than today UTC. Any other value returns 400 bad_request with error.param=date.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "view",
            "in": "query",
            "required": false,
            "description": "`totals` returns the counts without `markets`. Any other value than full or totals returns 400 bad_request with error.param=view.",
            "schema": {
              "type": "string",
              "enum": ["full", "totals"],
              "default": "full"
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Daily resolution report",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for this day's build and view. Re-send it via If-None-Match for conditional GETs.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "resolution_report"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ResolutionReport"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "resolution_report",
                      "data": {
                        "date": "2026-10-31",
                        "market_scope": "sports_and_esports",
                        "grade_basis": "at_resolution",
                        "total_resolved": 1240,
                        "with_smart_positions": 96,
                        "smart_money_right": 61,
                        "smart_money_wrong": 35,
                        "no_consensus": 1144,
                        "accuracy": 63.54166666666667,
                        "all_wallets_right": 55,
                        "all_wallets_wrong": 40,
                        "all_wallets_accuracy": 57.89473684210527,
                        "total_smart_pnl": 48210.5,
                        "markets_without_smart_positions": 1128,
                        "positions_grade_unknown": 0,
                        "positions_without_side": 3,
                        "time_basis_counts": {
                          "polymarket_gamma_closed_time": 1201,
                          "observed_resolution": 39
                        },
                        "generated_at": "2026-11-01T02:10:00+00:00",
                        "source_updates_pending": false,
                        "markets": [
                          {
                            "condition_id": "0x5f2c0a2b4d2e8e6b0f3c1a9d7e5b3c1a9d7e5b3c1a9d7e5b3c1a9d7e5b3c1a9d",
                            "title": "Lakers vs. Celtics",
                            "outcome_yes": "Lakers",
                            "outcome_no": "Celtics",
                            "event_slug": "nba-lal-bos-2026-10-31",
                            "category": "Sports",
                            "report_at": "2026-10-31T03:05:00Z",
                            "time_basis": "polymarket_gamma_closed_time",
                            "winning_outcome": 0,
                            "smart_consensus": "yes",
                            "smart_right": true,
                            "all_wallets_right": true,
                            "confidence": 0.42,
                            "smart_trader_count": 5,
                            "total_smart_pnl": 3120.25,
                            "weighted_yes": 7.1,
                            "weighted_no": 2.9,
                            "out_of_product_scope": false,
                            "traders": [
                              {
                                "address": "0x1234567890abcdef1234567890abcdef12345678",
                                "username": "example",
                                "grade": "A",
                                "side": "yes",
                                "correct": true,
                                "pnl": 1450.0,
                                "cost": 2100.0,
                                "last_traded_at": "2026-10-30T23:40:00Z"
                              }
                            ]
                          }
                        ]
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current Pick of the Day archive payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged Pick of the Day archive payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable. On this route a 503 has TWO distinct causes; branch on error.reason. (1) error.reason=\"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; consult that endpoint's contract and do not infer dependency health from this shared reason. This is endpoint-local unavailability, not rate limiting: retry only this route after Retry-After (or error.retry_at), and do not feed it into a rate-limit backoff shared with other endpoints. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the seconds until it probes Redis again. Both carry error.code=\"rate_limit_unavailable\" (a FROZEN contract value, so it cannot be split per cause) and X-Request-Id -- which is why error.reason, not error.code, is the discriminator.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until retrying is worth doing. With error.reason=\"read_model_warming\" this is the endpoint-local read-model retry interval; without a reason it is the rate-limiter outage cooldown. Always >= 1.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/reports/resolutions?date=2026-10-31'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/trader/{address}/export": {
      "get": {
        "operationId": "getTraderExportSnapshot",
        "summary": "Trader export snapshot metadata",
        "description": "Returns export source-range, completeness, volume reconciliation, row-count estimate, and large-export policy for one trader. To download the full dataset programmatically, POST to this same path to submit an async export job (json | ndjson | csv), then poll the status route and follow the download route once ready.",
        "tags": ["Traders"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "Trader wallet address (0x...), known trader username-style lookup, or trd_-prefixed trader ID emitted by this API. Bare integer database IDs are not accepted.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Trader export snapshot metadata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "trader_export_snapshot"
                    },
                    "data": {
                      "$ref": "#/components/schemas/TraderExportSnapshot"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "trader_export_snapshot",
                      "data": {
                        "address": "0xabc1230000000000000000000000000000000abc",
                        "product_scope": "sports_esports_v1",
                        "generated_at": "2026-09-22T03:22:08.147007+00:00",
                        "source_range": {
                          "first_pnl_date": "2026-01-16",
                          "last_pnl_date": "2026-09-10",
                          "pnl_series_status": "ready",
                          "latest_trade_at": "2026-09-09T21:24:10Z",
                          "latest_market_activity_at": "2026-09-09T21:24:10Z"
                        },
                        "completeness": {
                          "status": "partial",
                          "reason": "snapshot reflects currently synced local export read models; full raw trades remain a large async/streaming export path",
                          "sync_coverage": 0.9539438856537851
                        },
                        "reconciliation": {
                          "provider_lifetime_volume": null,
                          "exported_activity_volume": 612050.67,
                          "exported_market_cost_basis": 532742.31,
                          "provider_activity_volume_gap": null,
                          "activity_volume_coverage": null
                        },
                        "counts": {
                          "pnl_days": 238,
                          "exported_markets": 1802,
                          "estimated_trade_rows": 6986,
                          "estimated_size_mb": 2.8
                        },
                        "large_export_policy": {
                          "mode": "v1_async_export",
                          "current_internal_route": "/api/export/{address}/start",
                          "v1_async": {
                            "submit_route": "POST /api/v1/trader/{address}/export?format=json|ndjson|csv",
                            "status_route": "GET /api/v1/trader/{address}/export/status?job_id={id}",
                            "download_route": "GET /api/v1/trader/{address}/export/download?job_id={id}",
                            "cancel_route": "POST /api/v1/trader/{address}/export/cancel?job_id={id}",
                            "formats": ["json", "ndjson"],
                            "status_values": ["queued", "running"],
                            "retention": "ready jobs expire via export_jobs.expires_at (24h)"
                          },
                          "direct_streaming": {
                            "available_when": "internal export route only when R2 async export is not configured",
                            "backpressure": "database cursor streamed through bounded channel",
                            "chunk_size_rows": 1000
                          },
                          "async_job": {
                            "available_when": "internal export route when R2 async export is configured",
                            "status_values": ["queued", "running"],
                            "retention": "ready jobs expire via export_jobs.expires_at"
                          },
                          "rate_limit": {
                            "daily_cap_per_user": 20,
                            "per_address_hourly_cap": 5
                          }
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/trader/{address}/export'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "trader_export_snapshot",
            "data": {},
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["export"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      },
      "post": {
        "operationId": "submitTraderExport",
        "summary": "Submit a trader dataset export job",
        "description": "Queues an async export of the trader's full dataset in the requested format (json default, ndjson, or csv) and returns the job resource. Poll the status route at poll_after_s until terminal is true, then follow the download route while status is 'ready' (until expires_at, 24 hours from submit). Reuse: without fresh=true, a live job for the same trader and format inside its retention window (queued, running, reconcile_required or ready) is returned with 200 instead of a new one, except a job its owner asked to cancel, which is never reused; its data_as_of says what its file is a snapshot of. With fresh=true only a queued job (which has not started reading) is reused; a running, reconciling or ready job is left alone and a new job is reserved, which consumes quota like any new job. Both decisions run under one per-account lock, so two concurrent submits cannot both reserve when one would have reused the other. Quotas are the per-user daily and per-address hourly export caps, keyed on the API key owner so an API key never widens its owner's quota. New full exports select one database read generation before delivery. JSON and NDJSON add export_metadata.generation (id, selected_at, consistency=repeatable_read, source_watermarks for positions, native P&L, categories and all matching trades), position_generation, provider_observations (provider values and observation/revision metadata), category_data_as_of, pnl_date_from/to, pnl_rows, pnl_row_limit (3650), markets_rows, markets_row_limit (50000), summary_basis and trades_basis. Summary counts cover all stored markets; the markets section retains its existing latest-activity 50000-row limit and P&L its earliest-3650-days limit. These are database consistency and section coverage facts, not a claim that providers observed every section simultaneously. CSV appends export_generation, export_selected_at and export_consistency columns. Downloaded objects also expose x-amz-meta-export-generation, x-amz-meta-export-selected-at, x-amz-meta-export-consistency, x-amz-meta-export-trades and x-amz-meta-export-provenance headers, including empty CSV files. Historical artifacts remain unchanged. Select CSV columns by name; JSON/NDJSON readers may ignore the additive fields. A read exceeding 600 seconds or an uncompressed artifact exceeding 2 GiB fails without publishing a partial file.",
        "tags": ["Traders"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "Trader wallet address (0x...), known trader username-style lookup, or trd_-prefixed trader ID emitted by this API.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "Output serialization. json = full envelope document (default); ndjson = full envelope as line 1 then one trade object per line; csv = flat trades rows only.",
            "schema": {
              "type": "string",
              "enum": ["json", "ndjson", "csv"],
              "default": "json"
            }
          },
          {
            "name": "fresh",
            "in": "query",
            "required": false,
            "description": "true: do not reuse a finished, running or reconciling job; only a queued job is reused, so the file is a snapshot read after this submit. Consumes quota when nothing is queued. Default false.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A live job for this trader and format inside its retention window already exists and was reused; read its data_as_of and expires_at.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraderExportJob"
                },
                "examples": {
                  "reused": {
                    "summary": "Existing in-flight job reused (no new quota consumed)",
                    "value": {
                      "object": "trader_export_job",
                      "data": {
                        "job_id": 123,
                        "status": "running",
                        "format": "csv",
                        "total_trades": 4821,
                        "processed_trades": 1200,
                        "file_size": null,
                        "error": null,
                        "terminal": false,
                        "next_action": "poll",
                        "poll_after_s": 5,
                        "created_at": "2026-09-22T09:00:00Z",
                        "started_at": "2026-09-22T09:00:04Z",
                        "ready_at": null,
                        "failed_at": null,
                        "expires_at": "2026-09-23T09:00:00Z",
                        "expired_at": null,
                        "data_as_of": null,
                        "cancel_requested_at": null,
                        "cancelled_at": null,
                        "attempt": 1,
                        "max_attempts": 3
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 0
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "202": {
            "description": "New export job accepted and queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraderExportJob"
                },
                "examples": {
                  "queued": {
                    "summary": "New CSV export job queued",
                    "value": {
                      "object": "trader_export_job",
                      "data": {
                        "job_id": 123,
                        "status": "queued",
                        "format": "csv",
                        "total_trades": null,
                        "processed_trades": 0,
                        "file_size": null,
                        "error": null,
                        "terminal": false,
                        "next_action": "poll",
                        "poll_after_s": 5,
                        "created_at": "2026-09-22T09:00:00Z",
                        "started_at": null,
                        "ready_at": null,
                        "failed_at": null,
                        "expires_at": "2026-09-23T09:00:00Z",
                        "expired_at": null,
                        "data_as_of": null,
                        "cancel_requested_at": null,
                        "cancelled_at": null,
                        "attempt": 0,
                        "max_attempts": 3
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS -X POST \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/trader/{address}/export?format=csv'"
          }
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["export"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/trader/{address}/export/status": {
      "get": {
        "operationId": "getTraderExportStatus",
        "summary": "Poll a trader export job",
        "description": "Returns the job resource for a submitted export: status (queued | running | cancel_requested | reconcile_required | ready | failed | expired | cancelled), terminal, next_action and poll_after_s, the lifecycle timestamps, the retention window (expires_at) and, once the file is written, data_as_of and the artifact identity. A ready job past expires_at reads expired; a queued, running or reconciling job past expires_at reads failed. Work stops at retention safe points; completion and reconciliation cannot publish ready after expiry. The failure event carries failure_reason expired_before_completion and next_action resubmit; delivery never extends retention. A running job its owner cancelled reads cancel_requested until the worker stops, then cancelled. failed, cancelled and expired jobs stay readable for 48 hours, then 404.",
        "tags": ["Traders"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "Trader wallet address (0x...), known trader username-style lookup, or trd_-prefixed trader ID emitted by this API.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "job_id",
            "in": "query",
            "required": true,
            "description": "Export job id returned by the submit route.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Export job state",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraderExportJob"
                },
                "examples": {
                  "ready": {
                    "summary": "A ready job, downloadable until expires_at",
                    "value": {
                      "object": "trader_export_job",
                      "data": {
                        "job_id": 123,
                        "status": "ready",
                        "format": "csv",
                        "total_trades": 4821,
                        "processed_trades": 4821,
                        "file_size": 1893344,
                        "error": null,
                        "terminal": true,
                        "next_action": "download",
                        "created_at": "2026-09-22T09:00:00Z",
                        "started_at": "2026-09-22T09:00:04Z",
                        "ready_at": "2026-09-22T09:00:31Z",
                        "failed_at": null,
                        "expires_at": "2026-09-23T09:00:00Z",
                        "expired_at": null,
                        "data_as_of": "2026-09-22T08:58:12Z",
                        "cancel_requested_at": null,
                        "cancelled_at": null,
                        "attempt": 1,
                        "max_attempts": 3,
                        "artifact": {
                          "artifact_id": "export_artifact_123",
                          "etag": "\"3f2a9c1e5b7d4a6f8e0c2b4d6f8a0c2e-3\"",
                          "compressed_size_bytes": 412903,
                          "content_type": "text/csv",
                          "content_encoding": "gzip",
                          "manifest": {
                            "manifest_version": "1",
                            "format": "csv",
                            "schema_version": "trader-export-csv-v1",
                            "coverage": "trades_only",
                            "generation": {
                              "id": "9d3e8c45-56cc-47a6-a4f8-1e0f54e3e4d1",
                              "selected_at": "2026-09-22T09:00:05Z",
                              "consistency": "repeatable_read",
                              "source_watermarks": {
                                "positions": {
                                  "source": "trader_position_snapshots_or_traders_last_synced",
                                  "coverage": "position_snapshot",
                                  "generation": 42,
                                  "data_as_of": "2026-09-22T08:58:12Z"
                                },
                                "pnl": {
                                  "source": "trader_trading_pnl",
                                  "coverage": "native_provider",
                                  "revision": 17,
                                  "observed_at": "2026-09-22T08:58:12Z"
                                },
                                "categories": {
                                  "source": "trader_category_breakdown_runs",
                                  "coverage": "published_projection",
                                  "publication_fence": "2026-09-22T08:58:12Z",
                                  "data_as_of": "2026-09-22T08:58:12Z"
                                },
                                "trades": {
                                  "source": "trades",
                                  "coverage": "sports_esports_rows",
                                  "rows": 4821,
                                  "first_activity_date": "2024-01-01"
                                }
                              },
                              "product_scope": "sports_esports_v1"
                            },
                            "row_count": 4821,
                            "content_size_bytes": 1893344,
                            "content_sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
                            "compressed_size_bytes": 412903,
                            "compressed_sha256": "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"
                          }
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  },
                  "expired": {
                    "summary": "The same job after its retention window",
                    "value": {
                      "object": "trader_export_job",
                      "data": {
                        "job_id": 123,
                        "status": "expired",
                        "format": "csv",
                        "total_trades": 4821,
                        "processed_trades": 4821,
                        "file_size": 1893344,
                        "error": null,
                        "terminal": true,
                        "next_action": "resubmit",
                        "created_at": "2026-09-22T09:00:00Z",
                        "started_at": "2026-09-22T09:00:04Z",
                        "ready_at": "2026-09-22T09:00:31Z",
                        "failed_at": null,
                        "expires_at": "2026-09-23T09:00:00Z",
                        "expired_at": "2026-09-23T09:00:00Z",
                        "data_as_of": "2026-09-22T08:58:12Z",
                        "cancel_requested_at": null,
                        "cancelled_at": null,
                        "attempt": 1,
                        "max_attempts": 3
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/trader/{address}/export/status?job_id=123'"
          }
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["export"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/trader/{address}/export/cancel": {
      "post": {
        "operationId": "cancelTraderExport",
        "summary": "Cancel a trader export job",
        "description": "Cancels a submitted export and returns the job resource, the same shape the status route returns. A queued job reads cancelled at once and no worker will start it. A running job reads cancel_requested until the worker reaches its next safe point, then cancelled: the worker checks every 5 seconds while it reads the snapshot and between upload parts, and once more at the last point before the file is published; a storage request already in flight finishes first (each is bounded at 120 seconds), and a partial upload is discarded. If the worker itself stops first, the job reads cancelled as that worker shuts down for a deploy, and otherwise within a minute of its 30-minute lease lapsing. A job a cancel can no longer reach is returned unchanged with 200: once its upload is being completed it finishes as ready (or reconcile_required, then ready or failed), and ready, failed, expired and cancelled jobs are terminal. A cancel never deletes a ready file; compare status before and after. Repeating the request is safe: it converges on the same state and never repeats a transition, so a client that lost the answer can send it again or read the status route. While terminal is false, poll the status route after poll_after_s. Quota is unchanged: the submit's reservation keeps counting toward the per-user daily and per-address hourly export caps for its full window, as a failed export's does, and a job its owner asked to cancel is never reused by a later submit, which reserves a new job. Webhook endpoints subscribed to export_job_cancelled receive it when the job reaches cancelled. An unknown job id, or a job owned by another account or submitted for another trader, answers 404 exactly as the status route does.",
        "tags": ["Traders"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "Trader wallet address (0x...), known trader username-style lookup, or trd_-prefixed trader ID emitted by this API.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "job_id",
            "in": "query",
            "required": true,
            "description": "Export job id returned by the submit route.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The job after the cancel: cancelled, cancel_requested, or unchanged when a cancel can no longer reach it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraderExportJob"
                },
                "examples": {
                  "cancelled": {
                    "summary": "A queued job, cancelled before a worker started it",
                    "value": {
                      "object": "trader_export_job",
                      "data": {
                        "job_id": 123,
                        "status": "cancelled",
                        "format": "csv",
                        "total_trades": null,
                        "processed_trades": 0,
                        "file_size": null,
                        "error": null,
                        "terminal": true,
                        "next_action": "resubmit",
                        "created_at": "2026-09-22T09:00:00Z",
                        "started_at": null,
                        "ready_at": null,
                        "failed_at": null,
                        "expires_at": "2026-09-23T09:00:00Z",
                        "expired_at": null,
                        "data_as_of": null,
                        "cancel_requested_at": "2026-09-22T09:00:02Z",
                        "cancelled_at": "2026-09-22T09:00:02Z",
                        "attempt": 0,
                        "max_attempts": 3
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  },
                  "cancel_requested": {
                    "summary": "A running job; the worker stops at its next safe point",
                    "value": {
                      "object": "trader_export_job",
                      "data": {
                        "job_id": 123,
                        "status": "cancel_requested",
                        "format": "csv",
                        "total_trades": 4821,
                        "processed_trades": 4821,
                        "file_size": null,
                        "error": null,
                        "terminal": false,
                        "next_action": "poll",
                        "poll_after_s": 5,
                        "created_at": "2026-09-22T09:00:00Z",
                        "started_at": "2026-09-22T09:00:04Z",
                        "ready_at": null,
                        "failed_at": null,
                        "expires_at": "2026-09-23T09:00:00Z",
                        "expired_at": null,
                        "data_as_of": null,
                        "cancel_requested_at": "2026-09-22T09:00:20Z",
                        "cancelled_at": null,
                        "attempt": 1,
                        "max_attempts": 3
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  },
                  "unchanged_ready": {
                    "summary": "Too late: the file was already published, and the job is returned unchanged",
                    "value": {
                      "object": "trader_export_job",
                      "data": {
                        "job_id": 123,
                        "status": "ready",
                        "format": "csv",
                        "total_trades": 4821,
                        "processed_trades": 4821,
                        "file_size": 1893344,
                        "error": null,
                        "terminal": true,
                        "next_action": "download",
                        "created_at": "2026-09-22T09:00:00Z",
                        "started_at": "2026-09-22T09:00:04Z",
                        "ready_at": "2026-09-22T09:00:31Z",
                        "failed_at": null,
                        "expires_at": "2026-09-23T09:00:00Z",
                        "expired_at": null,
                        "data_as_of": "2026-09-22T08:58:12Z",
                        "cancel_requested_at": null,
                        "cancelled_at": null,
                        "attempt": 1,
                        "max_attempts": 3,
                        "artifact": {
                          "artifact_id": "export_artifact_123",
                          "etag": "\"3f2a9c1e5b7d4a6f8e0c2b4d6f8a0c2e-3\"",
                          "compressed_size_bytes": 412903,
                          "content_type": "text/csv",
                          "content_encoding": "gzip",
                          "manifest": {
                            "manifest_version": "1",
                            "format": "csv",
                            "schema_version": "trader-export-csv-v1",
                            "coverage": "trades_only",
                            "generation": {
                              "id": "9d3e8c45-56cc-47a6-a4f8-1e0f54e3e4d1",
                              "selected_at": "2026-09-22T09:00:05Z",
                              "consistency": "repeatable_read",
                              "source_watermarks": {
                                "positions": {
                                  "source": "trader_position_snapshots_or_traders_last_synced",
                                  "coverage": "position_snapshot",
                                  "generation": 42,
                                  "data_as_of": "2026-09-22T08:58:12Z"
                                },
                                "pnl": {
                                  "source": "trader_trading_pnl",
                                  "coverage": "native_provider",
                                  "revision": 17,
                                  "observed_at": "2026-09-22T08:58:12Z"
                                },
                                "categories": {
                                  "source": "trader_category_breakdown_runs",
                                  "coverage": "published_projection",
                                  "publication_fence": "2026-09-22T08:58:12Z",
                                  "data_as_of": "2026-09-22T08:58:12Z"
                                },
                                "trades": {
                                  "source": "trades",
                                  "coverage": "sports_esports_rows",
                                  "rows": 4821,
                                  "first_activity_date": "2024-01-01"
                                }
                              },
                              "product_scope": "sports_esports_v1"
                            },
                            "row_count": 4821,
                            "content_size_bytes": 1893344,
                            "content_sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
                            "compressed_size_bytes": 412903,
                            "compressed_sha256": "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"
                          }
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter: job_id missing or not an integer, or a malformed trader path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS -X POST \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/trader/{address}/export/cancel?job_id=123'"
          }
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["export"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/trader/{address}/export/download": {
      "get": {
        "operationId": "downloadTraderExport",
        "summary": "Download a finished trader export",
        "description": "Redirects (302) to a presigned URL lasting at most one hour and no later than the job's expires_at for the finished export file while the job status is 'ready' and expires_at has not passed. The file is gzip-compressed and served with the format's Content-Type (application/json, application/x-ndjson, or text/csv). Returns 400 while the job is queued, running, cancel_requested or reconciling (poll the status route first) and for a failed or cancelled job (submit a new export); returns 410 with error.code not_found and error.reason export_expired once the retention window has passed, less than one whole second remains when signing, or the file has been retired, so the redirect never points at a file that is gone.",
        "tags": ["Traders"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "Trader wallet address (0x...), known trader username-style lookup, or trd_-prefixed trader ID emitted by this API.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "job_id",
            "in": "query",
            "required": true,
            "description": "Export job id returned by the submit route.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to the presigned download URL.",
            "headers": {
              "Location": {
                "description": "Presigned export download URL valid for at most one hour, with X-Amz-Date + X-Amz-Expires no later than the job's expires_at. Treat it as a credential.",
                "required": true,
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "410": {
            "description": "The export's retention window has passed, less than one whole second remains when signing, or its file has been retired. error.code is not_found, error.reason is export_expired, error.message names expired_at. Submit a new export; polling or retrying the download cannot succeed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "expired": {
                    "summary": "Download after the retention window",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "not_found",
                        "message": "Export job 123 expired at 2026-09-23T09:00:00Z and its file is no longer available. Submit a new export.",
                        "doc_url": "https://docs.0xinsider.com/api-reference/endpoint/get-trader-export-status",
                        "reason": "export_expired"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sSL --compressed -o trader-dataset.csv \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/trader/{address}/export/download?job_id=123'"
          }
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["export"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/usage": {
      "get": {
        "tags": ["Usage"],
        "operationId": "getUsage",
        "summary": "Inspect current API usage without spending primary request quota",
        "description": "Returns the authenticated caller sliding-window request budget, UTC-day usage and monthly quota. This control-plane endpoint remains available for a valid credential after paid data access lapses and does not increment the primary Redis rate-limit counter, monthly quota or API usage table; it shares a separate 100 reads/minute per-user inspection bucket with GET /api/v1/me. UTC-day totals use finalized quarter-hour rollups plus the disjoint raw interval through request time; unavailable rollup progress returns an error. Late accounting records retain their original UTC day when closed-period usage is read or the monthly budget is rebuilt. Current periods reflect persisted records and remain provisional; quota limits, prices and response fields are unchanged.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["usage"]
          }
        ],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Usage budget and counters for the authenticated API key owner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usage"
                },
                "examples": {
                  "success": {
                    "summary": "Successful response",
                    "value": {
                      "object": "usage",
                      "data": {
                        "rate_limit": {
                          "used": 7,
                          "limit": 100,
                          "remaining": 93,
                          "reset_at": 1710772860,
                          "window_seconds": 60
                        },
                        "daily_usage": {
                          "used": 42,
                          "limit": null,
                          "remaining": null,
                          "reset_at": 1710806400,
                          "window_seconds": 86400
                        },
                        "monthly_quota": {
                          "used": 41230,
                          "limit": 500000,
                          "remaining": 458770,
                          "reset_at": 1793491200,
                          "enforced_from": 1790812800,
                          "binding": false,
                          "pay_as_you_go": false,
                          "ceiling": 500000,
                          "unavailable_reason": null
                        }
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Monthly-Quota-Limit": {
                "$ref": "#/components/headers/X-Monthly-Quota-Limit"
              },
              "X-Monthly-Quota-Remaining": {
                "$ref": "#/components/headers/X-Monthly-Quota-Remaining"
              },
              "X-Monthly-Quota-Reset": {
                "$ref": "#/components/headers/X-Monthly-Quota-Reset"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. GET /api/v1/me and GET /api/v1/usage share a separate control-plane inspection bucket of 100 reads/minute per user; these diagnostics do not spend the primary request or monthly quota. Honor Retry-After and the RateLimit-* headers. The per-address budget also applies.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/usage'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "usage",
            "data": {
              "rate_limit": {
                "used": 7,
                "limit": 100,
                "remaining": 93,
                "reset_at": 1710772860,
                "window_seconds": 60
              },
              "daily_usage": {
                "used": 42,
                "limit": null,
                "remaining": null,
                "reset_at": 1710806400,
                "window_seconds": 86400
              }
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/market/{condition_id}/context.md": {
      "get": {
        "operationId": "getMarketContextMarkdown",
        "summary": "Get market context (Markdown)",
        "description": "Authenticated, self-contained Polymarket market evidence document. Renders the same typed data as the market snapshot with trust included: identity, outcome labels and tokens, cached quotes, liquidity, live sports, and per-source freshness or unavailable reasons. Provider text is encoded as indented JSON data. Accepts raw or mkt_-prefixed condition IDs. Unknown markets return 404. No ETag or conditional requests; use the snapshot JSON route for those.",
        "tags": ["Markets"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "condition_id",
            "in": "path",
            "required": true,
            "description": "Market condition ID. Accepts the raw provider-backed condition_id returned by /api/v1/markets/search or /api/v1/markets/explore, or the mkt_-prefixed market.id emitted by V1 responses.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Market evidence document (Markdown)",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27303): the market is real but outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this market. Without error.reason, no stored market has this condition_id. Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/trader/{address}/context.md'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/me": {
      "get": {
        "tags": ["Account"],
        "operationId": "getAccountIdentity",
        "summary": "Identify the authenticated account and credential",
        "description": "Returns caller-owned account and credential IDs, credential validity, paid-data entitlement and approved scopes. Null scopes mean full legacy developer-key access. Valid credentials can use this control-plane diagnostic path after paid access lapses; data routes still require active paid access. OAuth grants and named integration keys need read scope. Does not return credentials, payment details or personal contact details.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["read"]
          }
        ],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated account and credential identity.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountIdentity"
                },
                "examples": {
                  "success": {
                    "summary": "The credential behind this request",
                    "value": {
                      "object": "account",
                      "data": {
                        "user_id": 1,
                        "credential_id": 83,
                        "credential_kind": "api_key",
                        "credential_status": "active",
                        "entitlement": {
                          "paid_data_access": "active",
                          "recovery_action": null
                        },
                        "scopes": null
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Monthly-Quota-Limit": {
                "$ref": "#/components/headers/X-Monthly-Quota-Limit"
              },
              "X-Monthly-Quota-Remaining": {
                "$ref": "#/components/headers/X-Monthly-Quota-Remaining"
              },
              "X-Monthly-Quota-Reset": {
                "$ref": "#/components/headers/X-Monthly-Quota-Reset"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. GET /api/v1/me and GET /api/v1/usage share a separate control-plane inspection bucket of 100 reads/minute per user; these diagnostics do not spend the primary request or monthly quota. Honor Retry-After and the RateLimit-* headers. The per-address budget also applies.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS \\\n  -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \\\n  'https://api.0xinsider.com/api/v1/me'"
          }
        ],
        "x-examples": {
          "success": {
            "object": "account",
            "data": {
              "user_id": 1,
              "credential_id": 83,
              "credential_kind": "api_key",
              "credential_status": "active",
              "entitlement": {
                "paid_data_access": "active",
                "recovery_action": null
              },
              "scopes": null
            },
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/datasets/whale-trades": {
      "post": {
        "operationId": "submitWhaleDataset",
        "summary": "Create an immutable whale dataset",
        "description": "Extract at most 1,000,000 rows and 256 MiB uncompressed; exceeding either bound fails the job and publishes no partial file. Window and filters freeze on admission; rows and source facts freeze on one worker database snapshot. NDJSON uses exact decimal strings, with no current grade or market enrichment. The manifest checkpoint includes already committed arrivals after to plus later/open writers, with intentional overlap. Paid export scope; jobs are private to the credential owner. Shares the 20/day owner export quota and fair worker admission with trader exports; datasets also have a combined 5/hour quota. Three worker attempts, 24-hour retention, no partial download; cancellation consumes its reservation. Coverage is whale alerts, not all provider fills. Sports and esports markets only (#27430): trades on any other market are left out of the file, and a condition_id naming such a market returns 404 not_found with error.reason market_out_of_scope before any job is reserved.",
        "tags": ["Traders"],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["export"]
          }
        ],
        "parameters": [],
        "responses": {
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "202": {
            "description": "Owner-scoped dataset lifecycle and immutable manifest when ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WhaleDatasetJob"
                }
              }
            }
          },
          "200": {
            "description": "Reused identical live dataset job.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WhaleDatasetJob"
                }
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "requestBody": {
          "required": true,
          "description": "Finite past [from, to) window up to 31 days, with optional stable source filters. Identical live normalized requests reuse their job without another reservation. A failed or expired job can be resubmitted.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["from", "to"],
                "properties": {
                  "from": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "to": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "condition_id": {
                    "type": "string",
                    "description": "Raw provider condition id or mkt_-prefixed id."
                  },
                  "min_size": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1000000000000000.0,
                    "description": "USD minimum, normalized to cents like replay."
                  }
                },
                "additionalProperties": false
              }
            }
          }
        }
      }
    },
    "/api/v1/datasets/whale-trades/{job_id}": {
      "get": {
        "operationId": "getWhaleDatasetStatus",
        "summary": "Read a whale dataset job",
        "description": "Read queued, running, cancel_requested, ready, failed, reconcile_required, expired or cancelled. Poll only while next_action is poll, after poll_after_s. Ready manifests contain count, content and compressed SHA-256, schema, filters, source, horizon, expiry and replay continuation. Deltas do not retain the finite time filter and can repeat rows; deduplicate by wt_ ID (payload.whale_alert_id when not expanded). This is an insertion feed, not update/delete CDC. Paid export scope; jobs are private to the credential owner. Shares the 20/day owner export quota and fair worker admission with trader exports; datasets also have a combined 5/hour quota. Three worker attempts, 24-hour retention, no partial download; cancellation consumes its reservation. Coverage is whale alerts, not all provider fills.",
        "tags": ["Traders"],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["export"]
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Dataset job ID returned by submit; another owner or a trader export returns 404.",
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "200": {
            "description": "Owner-scoped dataset lifecycle and immutable manifest when ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WhaleDatasetJob"
                }
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/datasets/whale-trades/{job_id}/download": {
      "get": {
        "operationId": "downloadWhaleDataset",
        "summary": "Download an immutable whale dataset",
        "description": "Download only a ready artifact; status handles failure and cancellation. Retired artifacts return 410 at serving time. Paid export scope; jobs are private to the credential owner. Shares the 20/day owner export quota and fair worker admission with trader exports; datasets also have a combined 5/hour quota. Three worker attempts, 24-hour retention, no partial download; cancellation consumes its reservation. Coverage is whale alerts, not all provider fills.",
        "tags": ["Traders"],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["export"]
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Dataset job ID returned by submit; another owner or a trader export returns 404.",
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "302": {
            "description": "Private redirect to the immutable gzip NDJSON object. Fetch without API Authorization. Content-Encoding gzip: decompress before parsing; each line conforms to WhaleDatasetTrade. URL validity is min(1 hour, remaining artifact retention); get a fresh URL after expiry.",
            "x-empty-body": true,
            "headers": {
              "Location": {
                "description": "Temporary signed R2 URL; never persist it as the artifact identity.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "410": {
            "description": "The export's retention window has passed and its file is retired. error.code is not_found, error.reason is export_expired, error.message names expired_at. Submit a new export; polling or retrying the download cannot succeed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "expired": {
                    "summary": "Download after the retention window",
                    "value": {
                      "object": "error",
                      "error": {
                        "code": "not_found",
                        "message": "Export job 123 expired at 2026-09-23T09:00:00Z and its file is no longer available. Submit a new export.",
                        "doc_url": "https://docs.0xinsider.com/api-reference/endpoint/get-trader-export-status",
                        "reason": "export_expired"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/datasets/whale-trades/{job_id}/cancel": {
      "post": {
        "operationId": "cancelWhaleDataset",
        "summary": "Cancel a whale dataset job",
        "description": "Cancel queued jobs immediately and request running jobs stop at their next safe point. Repeating cancel converges on the current state; cancellation after the completion fence leaves the artifact ready. Paid export scope; jobs are private to the credential owner. Shares the 20/day owner export quota and fair worker admission with trader exports; datasets also have a combined 5/hour quota. Three worker attempts, 24-hour retention, no partial download; cancellation consumes its reservation. Coverage is whale alerts, not all provider fills.",
        "tags": ["Traders"],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["export"]
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Dataset job ID returned by submit; another owner or a trader export returns 404.",
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "200": {
            "description": "Owner-scoped dataset lifecycle and immutable manifest when ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WhaleDatasetJob"
                }
              }
            }
          }
        },
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/pick-of-the-day/ledger/{pick_id}": {
      "get": {
        "operationId": "getPickOfTheDayLedgerEntry",
        "summary": "Read a pick proof by stable id",
        "description": "Public read of one published pick by its stable decimal-string pick_id. Same proof gating, canonical bytes, ETag and integrity failures as the ledger. Invalid ids return 400; absent or unpublished picks return 404. Withdrawal from recommendations or the archive does not remove a published ledger entry.",
        "tags": ["Pick of the Day"],
        "security": [],
        "parameters": [
          {
            "name": "pick_id",
            "description": "Stable positive pick row id as canonical decimal text.",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[1-9][0-9]*$"
            }
          },
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional GET validator from a previous ETag. Matching values return 304 Not Modified with an empty body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pick of the Day commitment ledger",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Stable validator for the current Pick of the Day ledger payload. Re-send it via If-None-Match for conditional GETs.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "pick_of_the_day_ledger_entry"
                    },
                    "data": {
                      "$ref": "#/components/schemas/PickOfTheDayLedgerEntry"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "success": {
                    "summary": "One published pick addressed by stable id",
                    "value": {
                      "object": "pick_of_the_day_ledger_entry",
                      "data": {
                        "state": "uncommitted",
                        "pick_date": "2026-06-22",
                        "pick_rank": 1,
                        "pre_commitment": true,
                        "outcome": "win",
                        "withdrawal_reason": null,
                        "matchup": "Spain vs. France",
                        "category": "Soccer",
                        "resolved_at": null,
                        "permalink": "https://0xinsider.com/pick-of-the-day/picks/1",
                        "payload": {
                          "backed_price": "0.6100",
                          "condition_id": "0xabc1230000000000000000000000000000000abc7f7f7f7f7f7f7f7f7f7f7f7f",
                          "kickoff": "2026-06-22T19:00:00Z",
                          "pick_date": "2026-06-22",
                          "pick_outcome_index": 0,
                          "pick_outcome_label": "Spain",
                          "pick_rank": 1,
                          "platform": "polymarket"
                        },
                        "pick_id": "1000",
                        "publication_order": 1,
                        "is_free_selection": true,
                        "supersedes_pick_id": null
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current Pick of the Day ledger payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged Pick of the Day ledger payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Integrity refusal: a ledger row failed a consistency check, for example a pending pick that arrived carrying a column that must stay withheld until it settles. The whole response is refused and the row logged, rather than publishing a partial or unsafe record; the body carries a generic message. A database connection failure answers 503 instead.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "400": {
            "description": "Invalid canonical positive decimal pick_id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Absent or unpublished stable pick id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS 'https://api.0xinsider.com/api/v1/pick-of-the-day/ledger'"
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/webhooks/{id}/verification-attempts": {
      "post": {
        "operationId": "createWebhookVerificationAttempt",
        "summary": "Admit asynchronous webhook verification",
        "description": "Additive asynchronous consent flow; the legacy POST /verify keeps its synchronous 200/422 behavior and retry policy. Commits one durable attempt and returns 202 without awaiting DNS or the receiver. Send the original verification_token. Optional Idempotency-Key replays the original admission response for the same endpoint/token identity; a changed request returns 422 and an in-flight matching key returns 409. Different keys for the same token revision recover the same attempt, including terminal attempts, without new receiver work. Poll status_url for current state; 202 is admission, not activation. A supervised worker sends the existing signed webhook.verification body with an additional verification_attempt_id and x-0xinsider-verification-attempt header, stable across at-least-once retries. Verify the timestamp/raw-body HMAC and answer 2xx. DNS is public-address-pinned; redirects and proxies are refused and response bodies are not read. Timeout/transport/429/5xx failures retry at most 4 attempts, with 5/15/45-second waits, until the earlier token deadline or 15-minute horizon. Other receiver statuses and URL/security refusals are terminal. Activation requires current owner eligibility, endpoint/token/URL/signing identity, unexpired attempt/token and valid lease. Configuration changes or disable/delete cancel obsolete work. Terminal ciphertext is erased; status exposes no token, signing secret, address or receiver body. History is available for 7 days.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhook endpoint id owned by the authenticated API key user.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional safe-retry key. Reuse the same value only when retrying the exact same mutation request body; a different body returns 422 and an in-flight matching request returns 409.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255
            },
            "example": "wh_idem_01HX7Y9ZQ4K7Z0Q2E4N6A8C1BF"
          }
        ],
        "requestBody": {
          "description": "Original verification token; never use the signing secret here.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookVerificationAttemptRequest"
              },
              "example": {
                "verification_token": "whv_example"
              }
            }
          }
        },
        "responses": {
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "The request body is over 1048576 bytes. error.code is bad_request, error.reason is payload_too_large and error.param is body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "415": {
            "description": "The body was not sent as Content-Type: application/json. error.code is bad_request, error.reason is unsupported_media_type and error.param is content-type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "422": {
            "description": "Idempotency-Key already used with a different endpoint/token request identity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "202": {
            "description": "Durable admission; poll status_url for activation or terminal outcome.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "webhook_verification_attempt"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookVerificationAttempt"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "queued": {
                    "summary": "Committed pending consent",
                    "value": {
                      "object": "webhook_verification_attempt",
                      "data": {
                        "id": "7534f3db-65d3-4fe8-9c1a-afd8328302e7",
                        "object": "webhook_verification_attempt",
                        "webhook_id": 1,
                        "state": "queued",
                        "outcome": null,
                        "attempt_count": 0,
                        "max_attempts": 4,
                        "expires_at": "2026-10-01T12:15:00Z",
                        "next_attempt_at": "2026-10-01T12:00:00Z",
                        "last_response_status": null,
                        "started_at": null,
                        "completed_at": null,
                        "created_at": "2026-10-01T12:00:00Z",
                        "updated_at": "2026-10-01T12:00:00Z",
                        "status_url": "/api/v1/webhooks/1/verification-attempts/7534f3db-65d3-4fe8-9c1a-afd8328302e7"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          },
          "409": {
            "description": "Matching idempotency operation is in progress or the endpoint is not pending verification",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS -X POST -H \"Authorization: Bearer $OXINSIDER_API_KEY\" -H \"Content-Type: application/json\" -H \"Idempotency-Key: verification-1\" -d '{\"verification_token\":\"whv_example\"}' \"https://api.0xinsider.com/api/v1/webhooks/1/verification-attempts\""
          }
        ],
        "x-examples": {
          "success": {
            "object": "webhooks",
            "data": {},
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["webhooks"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/webhooks/{id}/verification-attempts/{attempt_id}": {
      "get": {
        "operationId": "getWebhookVerificationAttempt",
        "summary": "Read webhook verification attempt status",
        "description": "Fresh primary-database status for one attempt owned by the authenticated account and webhook. queued/running means consent is pending; only verified activates the unchanged endpoint after receiver 2xx. failed/cancelled/expired are terminal. Polling never issues a challenge or restarts work. At expiry the read reports expired immediately, even before the worker persists expiry. A missing, deleted or cross-owner endpoint/attempt returns 404. Outcomes and actual HTTP status are sanitized; no token, ciphertext, signing secret, destination address or receiver response body is returned. Terminal history is retained for 7 days.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhook endpoint id owned by the authenticated API key user.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "attempt_id",
            "in": "path",
            "required": true,
            "description": "Verification attempt UUID returned by admission. Must belong to this webhook and account.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "The request body is over 1048576 bytes. error.code is bad_request, error.reason is payload_too_large and error.param is body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "415": {
            "description": "The body was not sent as Content-Type: application/json. error.code is bad_request, error.reason is unsupported_media_type and error.param is content-type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "200": {
            "description": "Current sanitized attempt state",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["object", "data", "meta"],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "webhook_verification_attempt"
                    },
                    "data": {
                      "$ref": "#/components/schemas/WebhookVerificationAttempt"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/ResponseMeta"
                    }
                  }
                },
                "examples": {
                  "queued": {
                    "summary": "Committed pending consent",
                    "value": {
                      "object": "webhook_verification_attempt",
                      "data": {
                        "id": "7534f3db-65d3-4fe8-9c1a-afd8328302e7",
                        "object": "webhook_verification_attempt",
                        "webhook_id": 1,
                        "state": "queued",
                        "outcome": null,
                        "attempt_count": 0,
                        "max_attempts": 4,
                        "expires_at": "2026-10-01T12:15:00Z",
                        "next_attempt_at": "2026-10-01T12:00:00Z",
                        "last_response_status": null,
                        "started_at": null,
                        "completed_at": null,
                        "created_at": "2026-10-01T12:00:00Z",
                        "updated_at": "2026-10-01T12:00:00Z",
                        "status_url": "/api/v1/webhooks/1/verification-attempts/7534f3db-65d3-4fe8-9c1a-afd8328302e7"
                      },
                      "meta": {
                        "request_id": "req_example",
                        "cached": false,
                        "cost": 1
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \"https://api.0xinsider.com/api/v1/webhooks/1/verification-attempts/7534f3db-65d3-4fe8-9c1a-afd8328302e7\""
          }
        ],
        "x-examples": {
          "success": {
            "object": "webhooks",
            "data": {},
            "meta": {
              "request_id": "req_example",
              "cached": false,
              "cost": 1
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["webhooks"]
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/combos/fills": {
      "get": {
        "operationId": "listComboFills",
        "summary": "List combo fills",
        "description": "Returns live Polymarket combo taker fills with exact decimal-string economics, wallet identities, grades, legs, conjunction results, and ingest coverage. Requires an active Pro or Max API key. Listing includes executions with price at most 0.95; use combo detail for complete history. Sports and esports only (#27449): a fill is listed only when every leg of its combo is a sports or esports market; a combo with a leg on any other market never appears, and filters, page sizes and continuations apply after that exclusion. Recent ordering uses an exclusive cursor; largest and payout use offsets. Continuations are based on page fullness and may lead to an empty final page.",
        "tags": ["Combos"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a prior response; a matching representation returns 304.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "result",
            "in": "query",
            "description": "CSV of pending, won, or lost; all clears the filter. Unknown results appear only in unfiltered lists.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "legs",
            "in": "query",
            "description": "CSV of 2, 3, 4, or 5+; all clears the filter. A combo matches any named pick count.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_stake",
            "in": "query",
            "description": "Minimum collateral in whole USDC.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 1000000000,
              "default": 0
            }
          },
          {
            "name": "min_multiplier",
            "in": "query",
            "description": "0 disables the filter; otherwise use 2..1000000. Minimum shares per dollar at execution.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 1000000,
              "default": 0,
              "not": {
                "const": 1
              }
            }
          },
          {
            "name": "grades",
            "in": "query",
            "description": "CSV of S, A, B, C, D, F; all clears the filter. Ungraded wallets do not match.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sports",
            "in": "query",
            "description": "CSV of nfl, ncaaf, nba, wnba, baseball, hockey, soccer, tennis, table-tennis, esports, mma, boxing, golf, cricket, f1, pickleball; all clears the filter. Matches when any leg belongs to a selected sport.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Recent is newest first; largest ranks collateral; payout ranks buy-fill shares and excludes sells.",
            "schema": {
              "type": "string",
              "enum": ["recent", "largest", "payout"],
              "default": "recent"
            }
          },
          {
            "name": "window",
            "in": "query",
            "description": "Defaults to all for recent and 24h for largest or payout.",
            "schema": {
              "type": "string",
              "enum": ["24h", "7d", "all"]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size. Integer values outside the range are clamped to 1..200.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Exclusive block_number:log_index cursor for recent only; send the returned next_cursor unchanged.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Offset for ranked largest or payout ordering; use returned next_offset.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 5000,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List combo fills",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComboFillsResponse"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "id": "example_fill",
                      "block_number": 80000000,
                      "log_index": 1,
                      "block_timestamp": "2026-10-08T09:00:00Z",
                      "tx_hash": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
                      "trader": "0xcccccccccccccccccccccccccccccccccccccccc",
                      "trader_name": null,
                      "trader_grade": null,
                      "last_traded_at": null,
                      "action": "buy",
                      "condition_id": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                      "outcome_index": 0,
                      "shares": "100",
                      "collateral_usdc": "25",
                      "price": "0.25",
                      "price_yes": "0.25",
                      "fee_usdc": "0.1",
                      "leg_count": null,
                      "status": "unknown",
                      "status_reason": "legs_not_indexed",
                      "won_legs": 0,
                      "payout_multiplier": "4",
                      "legs": []
                    }
                  ],
                  "sort": "recent",
                  "window": "all",
                  "limit": 50,
                  "coverage": {
                    "state": "live",
                    "ingest_enabled": true,
                    "cursors": [],
                    "max_lag_blocks": 0,
                    "oldest_cursor_update": null,
                    "lifecycle_lag_blocks": null,
                    "lifecycle_backfilling": false,
                    "computed_at": "2026-10-08T09:00:00Z"
                  },
                  "has_more": false,
                  "meta": {
                    "request_id": "req_example",
                    "cached": false,
                    "cost": 1
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Combo reads may be temporarily unavailable (code internal_error). A verified database outage uses code rate_limit_unavailable with reason database_unavailable. Middleware may also refuse rate-limit admission with code rate_limit_unavailable. Retry a transient read after a short delay; honor Retry-After when present. A sport filter whose index is still being built uses reason read_model_warming, with Retry-After and error.retry_at.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \"https://api.0xinsider.com/api/v1/combos/fills\""
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/combos/summary": {
      "get": {
        "operationId": "getCombosSummary",
        "summary": "Get live combo count",
        "description": "Returns the stored count of traded combos whose YES conjunction remains pending, with its computation timestamp. Sports and esports only (#27449): a combo with a leg outside them is not counted. Requires an active Pro or Max API key. The count is refreshed by the ingest owner at most every five minutes and cached for 60 seconds. A null live value is unknown, never zero.",
        "tags": ["Combos"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a prior response; a matching representation returns 304.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Get live combo count",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CombosSummaryResponse"
                },
                "example": {
                  "object": "combos_summary",
                  "data": {
                    "live": {
                      "count": 12,
                      "computed_at": "2026-10-08T09:00:00Z"
                    }
                  },
                  "meta": {
                    "request_id": "req_example",
                    "cached": false,
                    "cost": 1
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Combo reads may be temporarily unavailable (code internal_error). A verified database outage uses code rate_limit_unavailable with reason database_unavailable. Middleware may also refuse rate-limit admission with code rate_limit_unavailable. Retry a transient read after a short delay; honor Retry-After when present.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \"https://api.0xinsider.com/api/v1/combos/summary\""
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/combos/{condition_id}": {
      "get": {
        "operationId": "getCombo",
        "summary": "Get combo detail",
        "description": "Returns one Polymarket combo with its legs, conjunction result, all-time trade totals, newest 100 taker fills, lifecycle totals, and ingest coverage. Requires an active Pro or Max API key. Detail retains execution history above the listing price cap. A malformed combo ID returns 400; an unknown well-formed ID returns 404. A combo with a leg outside sports and esports returns 404 not_found with error.reason=market_out_of_scope (#27449). Null lifecycle or missing leg facts remain unknown.",
        "tags": ["Combos"],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "description": "ETag from a prior response; a matching representation returns 304.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "condition_id",
            "in": "path",
            "required": true,
            "description": "Combo identifier: 0x followed by 62 lowercase hex characters. This differs from a binary market condition ID.",
            "schema": {
              "type": "string",
              "description": "Combo identifier: 0x followed by 62 lowercase hex characters. This differs from a binary market condition ID.",
              "pattern": "^0x[0-9a-f]{62}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Get combo detail",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComboResponse"
                },
                "example": {
                  "object": "combo",
                  "data": {
                    "access": "full",
                    "combo": {
                      "condition_id": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                      "leg_count": null,
                      "prepared_at": null,
                      "legs_known": false,
                      "legs": [],
                      "window": null,
                      "totals": null,
                      "status": "unknown",
                      "status_reason": "legs_not_indexed"
                    },
                    "fills": [
                      {
                        "id": "example_fill",
                        "block_number": 80000000,
                        "log_index": 1,
                        "block_timestamp": "2026-10-08T09:00:00Z",
                        "tx_hash": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
                        "trader": "0xcccccccccccccccccccccccccccccccccccccccc",
                        "trader_name": null,
                        "trader_grade": null,
                        "last_traded_at": null,
                        "action": "buy",
                        "condition_id": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                        "outcome_index": 0,
                        "shares": "100",
                        "collateral_usdc": "25",
                        "price": "0.25",
                        "price_yes": "0.25",
                        "fee_usdc": "0.1",
                        "leg_count": null,
                        "status": "unknown",
                        "status_reason": "legs_not_indexed",
                        "won_legs": 0,
                        "payout_multiplier": "4",
                        "legs": []
                      }
                    ],
                    "lifecycle": null,
                    "coverage": {
                      "state": "live",
                      "ingest_enabled": true,
                      "cursors": [],
                      "max_lag_blocks": 0,
                      "oldest_cursor_update": null,
                      "lifecycle_lag_blocks": null,
                      "lifecycle_backfilling": false,
                      "computed_at": "2026-10-08T09:00:00Z"
                    }
                  },
                  "meta": {
                    "request_id": "req_example",
                    "cached": false,
                    "cost": 1
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not Modified. Returned when If-None-Match matches the current payload.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "description": "Validator for the unchanged payload.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Account access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until rate limit resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Combo reads may be temporarily unavailable (code internal_error). A verified database outage uses code rate_limit_unavailable with reason database_unavailable. Middleware may also refuse rate-limit admission with code rate_limit_unavailable. Retry a transient read after a short delay; honor Retry-After when present.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Not found. error.reason=\"market_out_of_scope\" (#27449): the combo is real but has a leg on a market outside product scope -- 0xinsider serves sports and esports markets only. This is terminal: stop requesting this combo. Without error.reason, no indexed combo preparation or fill exists for this well-formed condition_id. Both carry error.code=\"not_found\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -sS -H \"Authorization: Bearer $OXINSIDER_API_KEY\" \"https://api.0xinsider.com/api/v1/combos/{condition_id}\""
          }
        ],
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        }
      }
    },
    "/api/v1/edge-hunter": {
      "get": {
        "tags": ["Markets"],
        "operationId": "getEdgeHunter",
        "x-latency-budget": {
          "milliseconds": 250,
          "measurement": "response-ready",
          "requirement": "engineering-budget"
        },
        "summary": "Get Edge Hunter",
        "description": "Max-only canonical Edge Hunter API with board, signals and observations views. An active Pro credential receives 403 forbidden with reason max_plan_required. Default board admission and ordering remain compatible: B grade floor, 30-row cap, 48-hour kickoff horizon, full Max projection and both current outcome quotes. Board outcomes include nullable token_id; the full signal includes nullable backed token_id, ranked_at copied from the frozen signal_created_at, and the existing aggregate category_skill evidence. Quote ts/validated_at and metadata_updated_at retain their separate meanings; none is wallet entry cost. Board quotes read verified display-price and websocket caches only, with no inline provider request or request-triggered REST refresh. Uncached outcomes remain null; retained quotes keep their original observation clock and existing retention bound. Board category, min_grade and limit are configurable; horizon clamps 1..48 and cap clamps 1..30. total counts selected admitted rows before the cap.\n\nSignals exposes full ranked records and category-skill/source evidence with default B grade floor, 12-hour horizon (clamp 1..48), page limit 20 (clamp 1..100) and cursor. Observations requires wider_holder, in_play or emerging_pile and retains full records, verified token IDs, midpoint price marks, holder/provider/directional clocks, snapshot_as_of, degraded, degradation_reasons, coverage and source-generation/category funnel evidence. Required degradation_reasons records each operational cause with canonical sport or null for generation-wide evidence, and is empty only for a healthy generation. For sports and esports reads, the first four coverage counts stay global across cohort/category/selectors; selected_observations counts matching rows before pagination and returned_observations equals data.length. An unmappable legacy category retains its zero-work empty generation with all coverage counts zero and no degradation reasons, without reading the all-sports cache. Intentional capacity_limited input, the one-page holder bound (holder_scan_complete=false, counted in coverage.incomplete_holder_markets) and board_upcoming_status=not_configured do not by themselves degrade a generation. Reconciled terminals prove accounting, not complete holder coverage. Observation horizon stays 48 hours with 12-hour in-play kickoff lookback and 30-second live snapshot ceiling. In-play additionally requires a coherent nonfuture original live-source clock no older than 30 seconds at publication and every served reuse; compute and missed-pass grace never renew that clock. Provider-confirmed live membership is observed independently of rendered scores, quotes and holder enrichment. UI refresh-marker expiry or score invalidation alone does not invalidate a separately observed provider membership. Explicit provider-source invalidation or an invalid, incomplete, future, expired or missing source remains unavailable. When one scheduled observation refresh misses its deadline, other cohorts may keep serving the last snapshot for up to 45 more seconds, with its age in meta.cache_age_s and its completion time in snapshot_as_of; a second missed refresh in a row returns 503 read_model_warming. An expired in-play source returns 503 read_model_warming even within generation grace. Funnel diagnostics describe the warmed generation/category accounting rather than the selected league/type/ID input census. admission=most_held_48h with cohort=wider_holder opts in to the most-held selection instead of the default one: per sport, up to 8 markets kicking off within 48 hours, most graded holders first, then volume, then soonest kickoff, at most 4 per event, recomputed every refresh; every row carries admitted_by most_held_48h, the response echoes admission, and funnel, coverage and degradation describe that selection. Both wider_holder selections add departures: the markets whose card left that selection before kickoff, each with departed_at, the departed card's last_observed_at and a reason from the funnel's terminal vocabulary, so a reader can tell a move to view=signals (primary_slate_candidate) from a split holder pile. Every observations snapshot names in signals_as_of the view=signals snapshot whose listed markets it excluded from wider_holder. A sport's pregame wider_holder holders are fetched only while a wider_holder or emerging_pile request named that sport, or named no category, within the last 30 minutes (default and most_held_48h counted apart; in-play reads never pause). A request whose sport was not read, or one without a category while any sport was not, returns 503 read_model_warming with Retry-After: 45 and restarts those reads; the retry serves the same rows as before, and that sport's admitted markets count as capacity_limited in the global coverage counts while they were not read.\n\nEvery view accepts kind, sports, leagues, market_types, condition_ids, event_slugs, series_slugs and legacy category. Repeat array query keys or supply comma-separated values inside a key; at most 100 supplied values per axis before deduplication. Values normalize, sort and deduplicate. Lists match OR and axes match AND. Sports and machine leagues normalize case-insensitively; market_types/event_slugs/series_slugs remain trimmed exact case-sensitive provider strings. category=NFL reaches Football, while leagues=nfl selects NFL only. Selection runs before cap/pagination, binds advanced cursors/ETags, and is echoed in optional top-level selection whenever a selector or nonblank category is requested. Missing selected metadata excludes a row. Unknown well-formed market IDs or provider identities return empty results.\n\nEach row adds required nullable market_context for authoritative discovery. A frozen observed sidecar gives required nullable league, series_slug, market_type and metadata_updated_at; a pre-selector cached generation can yield context:null on an unselected read. metadata_updated_at is exactly local market_canonical.updated_at, never a provider observation clock or current-time fallback. A selected read without sidecar readiness returns 503 read_model_warming with Retry-After: 5, never silently wider results. SDK selected reads enforce strict query validation and require the echo.\n\nAll public views read warmed generations only; missing or stale readiness returns 503 read_model_warming with Retry-After: 5. Advanced views use private,no-cache with ETag/If-None-Match/304; no request holder/provider computation. Default board has no ETag/pagination and private,no-store. Invalid view-specific parameters return 400. Replaced snapshots or changed cursor-bound filters return cursor_expired. Price marks are market midpoints, not wallet entry cost; volume is provider taker shares. Nullable/omitted evidence and db_only/degraded provenance remain explicit. Analytics is not an execution instruction.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "oauth2": ["read"]
          }
        ],
        "parameters": [
          {
            "name": "X-Query-Validation",
            "in": "header",
            "required": false,
            "description": "Set to strict to reject unsupported query names. By default, unknown query names are ignored and reported in X-Query-Ignored.",
            "schema": {
              "type": "string",
              "enum": ["strict"]
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Conditional validator for view=signals or view=observations only. A semantic match returns 304 with no body. The default board does not emit ETag or return 304.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "view",
            "in": "query",
            "required": false,
            "description": "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.",
            "schema": {
              "type": "string",
              "enum": ["board", "signals", "observations"],
              "default": "board"
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "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.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cohort",
            "in": "query",
            "required": false,
            "description": "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.",
            "schema": {
              "type": "string",
              "enum": ["wider_holder", "in_play", "emerging_pile"]
            }
          },
          {
            "name": "admission",
            "in": "query",
            "required": false,
            "description": "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.",
            "schema": {
              "type": "string",
              "enum": ["most_held_48h", "most_held_48h_by_type"]
            }
          },
          {
            "name": "min_grade",
            "in": "query",
            "required": false,
            "description": "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.",
            "schema": {
              "type": "string",
              "enum": ["S", "A", "B"]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "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.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque canonical Edge Hunter cursor from next_cursor. Bound to view, every normalized selection axis, grade/horizon where applicable, source snapshot and ordering; observations also bind cohort, admission and emerging cutoff. Changed selections or replaced snapshots return cursor_expired. Rejected in board.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "horizon_hours",
            "in": "query",
            "required": false,
            "description": "Kickoff window for board (default 48) or signals (default 12). Integer values clamp to 1..48. Rejected for observations, whose pre-game universe is fixed at 48 hours with a 12-hour in-play kickoff lookback.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "All views: sports excludes the Esports bucket; esports selects only Esports. Omit for both. Combines with other selections using AND. Selected reads echo normalized selection and require frozen metadata readiness.",
            "schema": {
              "type": "string",
              "enum": ["sports", "esports"]
            }
          },
          {
            "name": "sports",
            "in": "query",
            "required": false,
            "style": "form",
            "explode": true,
            "description": "Canonical sport buckets, including Esports and Table Tennis, matched case-insensitively. Unknown names and league aliases such as NFL are rejected in sports; use category for legacy bucket aliases or leagues for exact league selection. Omission covers every sport admitted by the selected view. All views. Repeat this query key or put comma-separated values inside a value. Values normalize, sort and deduplicate; at most 100 supplied values before deduplication. Values within this axis match OR; different selected axes match AND. An empty selection is invalid. Filtering precedes the board cap or advanced pagination and is bound to advanced cursors and ETags.",
            "schema": {
              "type": "array",
              "minItems": 1,
              "maxItems": 100,
              "items": {
                "type": "string",
                "minLength": 1
              }
            }
          },
          {
            "name": "leagues",
            "in": "query",
            "required": false,
            "style": "form",
            "explode": true,
            "description": "Normalized machine/provider league identities, such as nfl, cfb, nba, epl, cs2, lol, dota2 or valorant. Known wire/tag aliases normalize; other provider keys match exact lowercase identity. This is separate from category: category=NFL selects Football, while leagues=nfl selects NFL only. Read market_context.league for authoritative values. All views. Repeat this query key or put comma-separated values inside a value. Values normalize, sort and deduplicate; at most 100 supplied values before deduplication. Values within this axis match OR; different selected axes match AND. An empty selection is invalid. Filtering precedes the board cap or advanced pagination and is bound to advanced cursors and ETags.",
            "schema": {
              "type": "array",
              "minItems": 1,
              "maxItems": 100,
              "items": {
                "type": "string",
                "minLength": 1
              }
            }
          },
          {
            "name": "market_types",
            "in": "query",
            "required": false,
            "style": "form",
            "explode": true,
            "description": "Exact provider sports_market_type values. This is an open provider taxonomy, distinct from exact market IDs. Read market_context.market_type; missing selected metadata excludes the row. All views. Repeat this query key or put comma-separated values inside a value. Values normalize, sort and deduplicate; at most 100 supplied values before deduplication. Values within this axis match OR; different selected axes match AND. An empty selection is invalid. Filtering precedes the board cap or advanced pagination and is bound to advanced cursors and ETags.",
            "schema": {
              "type": "array",
              "minItems": 1,
              "maxItems": 100,
              "items": {
                "type": "string",
                "minLength": 1
              }
            }
          },
          {
            "name": "condition_ids",
            "in": "query",
            "required": false,
            "style": "form",
            "explode": true,
            "description": "Exact market selections. Raw provider condition IDs and the existing mkt_-prefixed aliases normalize to raw IDs. Unknown well-formed IDs return an empty result. All views. Repeat this query key or put comma-separated values inside a value. Values normalize, sort and deduplicate; at most 100 supplied values before deduplication. Values within this axis match OR; different selected axes match AND. An empty selection is invalid. Filtering precedes the board cap or advanced pagination and is bound to advanced cursors and ETags.",
            "schema": {
              "type": "array",
              "minItems": 1,
              "maxItems": 100,
              "items": {
                "type": "string",
                "minLength": 1
              }
            }
          },
          {
            "name": "event_slugs",
            "in": "query",
            "required": false,
            "style": "form",
            "explode": true,
            "description": "Exact provider event slugs. Use event_slug returned on the row; no title or slug-prefix guessing. All views. Repeat this query key or put comma-separated values inside a value. Values normalize, sort and deduplicate; at most 100 supplied values before deduplication. Values within this axis match OR; different selected axes match AND. An empty selection is invalid. Filtering precedes the board cap or advanced pagination and is bound to advanced cursors and ETags.",
            "schema": {
              "type": "array",
              "minItems": 1,
              "maxItems": 100,
              "items": {
                "type": "string",
                "minLength": 1
              }
            }
          },
          {
            "name": "series_slugs",
            "in": "query",
            "required": false,
            "style": "form",
            "explode": true,
            "description": "Exact provider series slugs. Read market_context.series_slug; a missing selected series excludes the row. All views. Repeat this query key or put comma-separated values inside a value. Values normalize, sort and deduplicate; at most 100 supplied values before deduplication. Values within this axis match OR; different selected axes match AND. An empty selection is invalid. Filtering precedes the board cap or advanced pagination and is bound to advanced cursors and ETags.",
            "schema": {
              "type": "array",
              "minItems": 1,
              "maxItems": 100,
              "items": {
                "type": "string",
                "minLength": 1
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One of the full board, ranked signals collection or cohort observations collection, selected by view. ETag is emitted only for advanced views; Cache-Control is private, no-cache for both advanced views.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "description": "For signals and observations: private, no-cache, requiring revalidation before reuse. The current quote board remains no-store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/EdgeHunterBoardResponse"
                    },
                    {
                      "$ref": "#/components/schemas/EdgeHunterSignalsResponse"
                    },
                    {
                      "$ref": "#/components/schemas/EdgeHunterObservationsResponse"
                    }
                  ]
                },
                "example": {
                  "object": "edge_hunter",
                  "data": {
                    "as_of": "2026-10-11T18:00:00Z",
                    "horizon_hours": 48,
                    "min_grade": "B",
                    "ranking_source": "live",
                    "directional_source": "live",
                    "cached_age_seconds": null,
                    "viewer": "max",
                    "free_rank": null,
                    "total": 0,
                    "rows": []
                  },
                  "meta": {
                    "request_id": "req_example",
                    "cached": false,
                    "cost": 5
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid view, selector value or view-specific query value; empty or over-100 selector list; bracket selector name; missing observation cohort; parameter belonging to another view; invalid/mismatched cursor or cursor_expired after a snapshot refresh. Send integers for horizon_hours and limit and S/A/B for board or signals min_grade. With X-Query-Validation: strict, an unsupported query name returns unknown_query_parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "402": {
            "description": "Active Pro or Max subscription required for paid data. Edge Hunter additionally requires Max; an active Pro credential receives 403 max_plan_required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. error.reason max_plan_required: the key is valid and its account is on Pro, but this route is part of Max; every Pro route keeps working with the same key, and error.message names the upgrade URL (https://0xinsider.com/pricing). Without a reason, the account was deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "408": {
            "description": "The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "423": {
            "description": "Account is locked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds before retrying when a warmed generation or required selection sidecar is unavailable; 5 for read_model_warming. Also applies to admission overload where documented.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "A fresh warmed generation or required frozen selection sidecar is unavailable for any view. No request holder/provider computation occurs. Retry-After: 5 identifies the bounded retry time; missing metadata never widens a selected result. For view=observations with cohort=wider_holder or emerging_pile it also means no request named this sport (or, without a category, one of the sports) in the last 30 minutes, so the generation did not read its pregame holders: the request restarts those reads, Retry-After is 45 and the retry normally serves.",
            "headers": {
              "Retry-After": {
                "description": "Seconds before retrying when a warmed generation or required selection sidecar is unavailable; 5 for read_model_warming, or 45 when an observation sport's pregame reads had paused for want of a reader. Also applies to admission overload where documented.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "304": {
            "description": "Advanced views only: If-None-Match matches the semantic signals or observation representation. No body. The default board never returns 304.",
            "headers": {
              "X-Query-Ignored": {
                "$ref": "#/components/headers/X-Query-Ignored"
              },
              "X-Effective-Query": {
                "$ref": "#/components/headers/X-Effective-Query"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Cache-Control": {
                "description": "Client caches may store the private response but must revalidate it before every reuse, independently of the server-side snapshot TTL.",
                "schema": {
                  "type": "string",
                  "const": "private, no-cache"
                }
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-Usage-Accounting": {
                "$ref": "#/components/headers/X-Usage-Accounting"
              },
              "Server-Timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "x-empty-body": true
          }
        }
      }
    }
  },
  "webhooks": {
    "large_trade_inserted_v2": {
      "post": {
        "summary": "large_trade_inserted_v2",
        "description": "One durable Polymarket large trade with a stable event ID and event-time trade facts. Filtered subscriptions receive matching trades without a follow-up feed request; replay uses GET /api/v1/events/feed/since with its own cursor.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "large_trade_inserted_v2"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/LargeTradeInsertedV2Data"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "large_trades_inserted": {
      "post": {
        "summary": "large_trades_inserted",
        "description": "Fires when new large trades are ingested. Successor spelling of whale_trades_inserted: the same event, delivered as `type: large_trades_inserted` to an endpoint that registered this name.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "large_trades_inserted"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/LargeTradesInsertedData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "whale_trades_inserted": {
      "post": {
        "summary": "whale_trades_inserted",
        "description": "Fires when new large trades are ingested. Deprecated spelling of large_trades_inserted: until its sunset on 2027-02-01 (#29352), an endpoint registered under this name keeps receiving `type: whale_trades_inserted`; subscribe to large_trades_inserted instead.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "whale_trades_inserted"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/LargeTradesInsertedData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "live_sports_updated": {
      "post": {
        "summary": "live_sports_updated",
        "description": "Fires on a bounded per-game pulse when a live game's scores, status, period or live/ended state moves. At most one delivery per game per 20 seconds; a live or ended transition is never coalesced away; the game clock alone never fires one.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "live_sports_updated"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/LiveSportsUpdatedData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "trader_synced": {
      "post": {
        "summary": "trader_synced",
        "description": "Fires after a tracked trader finishes syncing and has a fresh grade. Successor spelling of whale_trader_synced: the same event, delivered as `type: trader_synced` to an endpoint that registered this name.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "trader_synced"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/TraderSyncedData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "whale_trader_synced": {
      "post": {
        "summary": "whale_trader_synced",
        "description": "Fires after a tracked trader finishes syncing and has a fresh grade. Deprecated spelling of trader_synced: until its sunset on 2027-02-01 (#29352), an endpoint registered under this name keeps receiving `type: whale_trader_synced`; subscribe to trader_synced instead.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "whale_trader_synced"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/TraderSyncedData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "large_positions_updated": {
      "post": {
        "summary": "large_positions_updated",
        "description": "Fires when new large positions are detected or refreshed.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "large_positions_updated"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/LargePositionsUpdatedData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "wallet_grade_changed": {
      "post": {
        "summary": "wallet_grade_changed",
        "description": "Fires when a wallet's grade transitions on a Pass-2 re-grade.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "wallet_grade_changed"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/WalletGradeChangedData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "suspicious_trade_flagged": {
      "post": {
        "summary": "suspicious_trade_flagged",
        "description": "Fires the first time a trade's suspicion score crosses the flag threshold. Successor spelling of insider_radar_flag_raised: the same event, delivered as `type: suspicious_trade_flagged` to an endpoint that registered this name.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "suspicious_trade_flagged"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/SuspiciousTradeFlaggedData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "insider_radar_flag_raised": {
      "post": {
        "summary": "insider_radar_flag_raised",
        "description": "Fires the first time a trade's suspicion score crosses the flag threshold. Deprecated spelling of suspicious_trade_flagged: until its sunset on 2027-02-01 (#29352), an endpoint registered under this name keeps receiving `type: insider_radar_flag_raised`; subscribe to suspicious_trade_flagged instead.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "insider_radar_flag_raised"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/SuspiciousTradeFlaggedData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "sharp_money_flow_detected": {
      "post": {
        "summary": "sharp_money_flow_detected",
        "description": "Fires when ranked-trader net flow on a market crosses the sharp-money flow threshold (up or down). Successor spelling of smart_money_flow_detected: the same event, delivered as `type: sharp_money_flow_detected` to an endpoint that registered this name.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "sharp_money_flow_detected"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/SharpMoneyFlowDetectedData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "smart_money_flow_detected": {
      "post": {
        "summary": "smart_money_flow_detected",
        "description": "Fires when ranked-trader net flow on a market crosses the sharp-money flow threshold (up or down). Deprecated spelling of sharp_money_flow_detected: until its sunset on 2027-02-01 (#29352), an endpoint registered under this name keeps receiving `type: smart_money_flow_detected`; subscribe to sharp_money_flow_detected instead.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "smart_money_flow_detected"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/SharpMoneyFlowDetectedData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "export_job_ready": {
      "post": {
        "summary": "export_job_ready",
        "description": "Fires when an owner's asynchronous trader export is ready to download.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "export_job_ready"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/ExportJobReadyData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "export_job_failed": {
      "post": {
        "summary": "export_job_failed",
        "description": "Fires when an owner's asynchronous trader export reaches a terminal failed state.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "export_job_failed"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/ExportJobFailedData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "export_job_expired": {
      "post": {
        "summary": "export_job_expired",
        "description": "Fires when an owner's completed trader export reaches its retention boundary.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "export_job_expired"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/ExportJobExpiredData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "export_job_cancelled": {
      "post": {
        "summary": "export_job_cancelled",
        "description": "Fires when an owner's asynchronous trader export stops because its owner cancelled it.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "export_job_cancelled"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/ExportJobCancelledData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    },
    "market_price_moved": {
      "post": {
        "summary": "market_price_moved",
        "description": "Fires when a sports or esports market's outcome-0 midpoint moves at least your price_move_filters.min_move_cents over price_move_filters.window_seconds (60, 120, 300 or 900), measured from the Polymarket CLOB stream on a book with orders on both sides. At most one delivery per market per window: a later event inside the same window fires only for a larger move in the same direction. Carries the spread, the USD resting within 2 cents of the midpoint, the game's live state, and the large trades over the same window: all of them counted, and the ranked-wallet (grade B or better) flow among them; a missing value is null with a reason. A final game never fires. Pro and Max only.",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignatureHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestampHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookEventTypeHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookIdempotencyKeyHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryIdHeader"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttemptHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "type", "created_at", "data"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Stable event id, identical across retries of the same logical event."
                  },
                  "type": {
                    "type": "string",
                    "const": "market_price_moved"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the producer recorded the event; for a trade event, the fill time. Retries resend the same body, so it is not the time of the attempt."
                  },
                  "data": {
                    "$ref": "#/components/schemas/MarketPriceMovedData"
                  }
                }
              },
              "examples": {
                "nba_moneyline_before_tip": {
                  "summary": "NBA moneyline, 6-cent move over 5 minutes before tip",
                  "description": "Heat at Warriors, 2026-11-05, six hours before tip. The market, the prices (Polymarket's recorded price history: 0.305 at 20:44:21Z, 0.365 at 20:47:30Z) and the one large trade in the window (a $25,600 Warriors buy by a wallet graded C, so it counts in large_trades_in_window but not in ranked_large_trades) are real. The quote, the book depth and the sub-second timestamps were not recorded and are illustrative. The game had no live state yet and tipped at 03:00Z, after detected_at, so phase is pre_game. The episode first reported level 4, so this event carries previous_level_cents 4 and level_cents 6: a subscription with min_move_cents 5 or 6 receives it, one with 2, 3 or 4 received the level-4 event. Post this body to your receiver to test parsing before a live move arrives.",
                  "value": {
                    "id": "evt_market_price_moved_0xf20cb5106e675ff9ce2c2ee8ecffec367ca39e243efa2e6b4d8516b71aa93484_300s_1793911650412_6c",
                    "type": "market_price_moved",
                    "created_at": "2026-11-05T20:47:30.412Z",
                    "data": {
                      "condition_id": "0xf20cb5106e675ff9ce2c2ee8ecffec367ca39e243efa2e6b4d8516b71aa93484",
                      "event_slug": "nba-mia-gsw-2026-11-05",
                      "market_slug": "nba-mia-gsw-2026-11-05",
                      "league": "nba",
                      "outcome_index": 0,
                      "label": "Heat",
                      "direction": "up",
                      "from_price": "0.305",
                      "to_price": "0.365",
                      "move_cents": "6.000",
                      "level_cents": 6,
                      "previous_level_cents": 4,
                      "window_seconds": 300,
                      "window_start": "2026-11-05T20:42:30.412Z",
                      "observed_at": "2026-11-05T20:47:30.287Z",
                      "detected_at": "2026-11-05T20:47:30.412Z",
                      "best_bid": "0.36",
                      "best_ask": "0.37",
                      "spread_cents": "1.00",
                      "book_depth_within_2c": {
                        "bid_usd": "8412.35",
                        "ask_usd": "5236.80",
                        "book_observed_at": "2026-11-05T20:47:29.903Z"
                      },
                      "book_depth_unavailable_reason": null,
                      "phase": "pre_game",
                      "game_state": null,
                      "game_state_unavailable_reason": "no_game_state",
                      "concurrent_sharp_flow": {
                        "detected": false,
                        "net_flow_usd": 0.0,
                        "ranked_large_trades": 0,
                        "large_trades_in_window": 1,
                        "grade_floor": "B"
                      },
                      "concurrent_sharp_flow_unavailable_reason": null,
                      "gap_before": false,
                      "source": "clob_market_stream"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the delivery. Any other status, a redirect, a timeout or a connection error is retried on the published retry policy."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Legacy default or named integration API key, or OAuth 2.1 access token, in the Authorization header as `Bearer oxi_sk_live_...` or `Bearer oxi_at_...`. Default keys retain full access; integration keys are limited to their approved read, webhooks, export and usage scopes and expire within 90 days. All credentials share the owner's account limits. Data calls require an active Pro subscription and return live data. A 401 carries WWW-Authenticate: Bearer resource_metadata=\"https://api.0xinsider.com/.well-known/oauth-protected-resource\" (RFC 6750 section 3, RFC 9728)."
      },
      "oauth2": {
        "type": "oauth2",
        "description": "OAuth 2.1 authorization code flow with PKCE S256 for apps and MCP clients acting for a user. Public clients only (no client secret): register with RFC 7591 at https://api.0xinsider.com/oauth/register or present an https client ID metadata document URL as client_id. Authorization server metadata: https://api.0xinsider.com/.well-known/oauth-authorization-server. The access token (oxi_at_..., one hour) is sent as `Authorization: Bearer`; refresh tokens rotate on every use. A route outside the token's scopes answers 403 insufficient_scope. Walkthrough: https://0xinsider.com/auth.md.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://0xinsider.com/oauth/authorize",
            "tokenUrl": "https://api.0xinsider.com/oauth/token",
            "refreshUrl": "https://api.0xinsider.com/oauth/token",
            "scopes": {
              "read": "Read markets, traders, large trades, positions, reports, search, the event stream and every MCP tool",
              "webhooks": "Create, list, verify, rotate and delete webhook endpoints",
              "export": "Start, poll and download trader exports",
              "usage": "Read the caller's API usage counters"
            }
          }
        }
      }
    },
    "parameters": {
      "WebhookEventIdHeader": {
        "name": "x-0xinsider-event-id",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The event id, equal to the body `id`."
      },
      "WebhookEventTypeHeader": {
        "name": "x-0xinsider-event-type",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The event type the endpoint registered, equal to the body `type`."
      },
      "WebhookIdempotencyKeyHeader": {
        "name": "idempotency-key",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Stable key of this logical delivery (`whdel_...`). Every retry repeats it, so deduplicate on it."
      },
      "WebhookDeliveryIdHeader": {
        "name": "x-0xinsider-delivery-id",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Numeric id of this delivery, as a decimal string."
      },
      "WebhookDeliveryAttemptHeader": {
        "name": "x-0xinsider-delivery-attempt",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The delivery attempt counter, as a decimal string."
      },
      "WebhookTimestampHeader": {
        "name": "x-0xinsider-timestamp",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Unix seconds when this attempt was signed. Reject a delivery whose timestamp is more than 300 seconds from your clock."
      },
      "WebhookSignatureHeader": {
        "name": "x-0xinsider-signature",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "`v1=` followed by the hex HMAC-SHA256 of `{timestamp}.{raw body}` under the endpoint signing secret. During a staged secret rotation, or while 0xinsider rotates the key every signing secret is derived from, it carries up to four comma-separated `v1=` candidates, the current secret's first: accept the delivery when any one verifies."
      },
      "WebhookId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Webhook endpoint id owned by the authenticated API key user.",
        "schema": {
          "type": "integer",
          "format": "int64"
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Optional safe-retry key. Reuse the same value only when retrying the exact same mutation request body; a different body returns 422 and an in-flight matching request returns 409.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 255
        },
        "example": "wh_idem_01HX7Y9ZQ4K7Z0Q2E4N6A8C1BF"
      },
      "X-Query-Validation": {
        "name": "X-Query-Validation",
        "in": "header",
        "required": false,
        "description": "Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.",
        "schema": {
          "type": "string",
          "enum": ["strict"]
        }
      }
    },
    "schemas": {
      "CategoryLeader": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string"
          },
          "as_of": {
            "type": "string",
            "format": "date-time"
          },
          "category": {
            "type": "string"
          },
          "edge_lower_bound": {
            "type": ["number", "null"]
          },
          "grade": {
            "anyOf": [
              {
                "type": "string",
                "enum": ["S", "A", "B", "C", "D", "F"]
              },
              {
                "type": "null"
              }
            ]
          },
          "id": {
            "type": "string"
          },
          "independent_events": {
            "type": "integer"
          },
          "n_resolved": {
            "type": ["integer", "null"]
          },
          "platform": {
            "type": "string",
            "enum": ["polymarket"]
          },
          "pnl": {
            "type": ["number", "null"]
          },
          "rank": {
            "type": "integer"
          },
          "unresolved_events": {
            "type": "integer"
          },
          "username": {
            "type": ["string", "null"]
          },
          "win_rate": {
            "type": ["number", "null"]
          }
        },
        "required": [
          "rank",
          "category",
          "id",
          "address",
          "username",
          "platform",
          "grade",
          "edge_lower_bound",
          "independent_events",
          "unresolved_events",
          "n_resolved",
          "win_rate",
          "pnl",
          "as_of"
        ]
      },
      "LeaderboardLeagues": {
        "type": "object",
        "description": "Every league with a skill leaderboard, by sport: the league values GET /api/v1/leaderboard/sports/{sport} accepts.",
        "properties": {
          "leagues": {
            "type": "array",
            "description": "Grouped by sport, then most ranked wallets first.",
            "items": {
              "type": "object",
              "required": ["category", "sport", "slug", "name", "ranked_traders", "total_traders"],
              "properties": {
                "category": {
                  "type": "string",
                  "description": "The canonical sport, for example Soccer or Esports."
                },
                "name": {
                  "type": "string",
                  "description": "The league's display name."
                },
                "ranked_traders": {
                  "type": "integer",
                  "description": "Wallets the league board's edge sort ranks with no hold; at least min_ranked."
                },
                "slug": {
                  "type": "string",
                  "description": "The league slug, the board route's league parameter."
                },
                "sport": {
                  "type": "string",
                  "description": "The sport slug, the board route's {sport}."
                },
                "total_traders": {
                  "type": "integer",
                  "description": "Wallets with at least min_resolved settled markets in the league and a trade in the last 180 days: the field the league board ranks."
                }
              }
            }
          },
          "min_ranked": {
            "type": "integer",
            "description": "Wallets a league board's edge sort must rank, with no hold, for the league to be listed."
          },
          "min_resolved": {
            "type": "integer",
            "description": "Settled markets of $20 or more a wallet needs in a league to be on its board."
          },
          "refreshed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the league ranking last ran. It runs about once a day."
          }
        },
        "required": ["min_ranked", "min_resolved", "leagues", "refreshed_at"]
      },
      "SportLeaderboard": {
        "type": "object",
        "description": "One sport's skill leaderboard, or one league's. Every figure on a row is the wallet's record in this sport or league, except grade, the wallet's all-time grade, and volume (see volume_scope).",
        "properties": {
          "as_of": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "The latest time any wallet's record on this board was recomputed. The sport ranking reruns hourly, a league ranking about once a day. null when the board has no rows."
          },
          "category": {
            "type": ["string", "null"],
            "description": "The canonical sport the slug resolved to, for example Soccer or Basketball. null when no wallet has a record under it; rows is then empty."
          },
          "edge_average": {
            "type": ["number", "null"],
            "description": "The mean edge over every wallet in the field whose price_edge.status is ranked, held ones included: the value each row's edge_skill is pulled toward. null when no wallet's edge is ranked."
          },
          "league": {
            "description": "The league this board ranks; null on a sport board.",
            "anyOf": [
              {
                "type": "object",
                "required": ["slug", "name", "ranked_traders"],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "The league's display name."
                  },
                  "ranked_traders": {
                    "type": "integer",
                    "description": "Wallets the league board's edge sort ranks with no hold."
                  },
                  "slug": {
                    "type": "string",
                    "description": "The league's slug under its sport, for example premier-league or cs2."
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "type": "integer",
            "description": "The requested limit after clamping to 1..100 (default 20). rows holds fewer when the board has fewer wallets."
          },
          "min_resolved": {
            "type": "integer",
            "description": "Settled markets of $20 or more a wallet needs in the sport or league to be on the board."
          },
          "rows": {
            "type": "array",
            "description": "The head of the board, in sort order. Every figure is the wallet's record in this sport or league, except grade (all-time) and volume (see volume_scope).",
            "items": {
              "type": "object",
              "required": [
                "rank",
                "id",
                "address",
                "username",
                "platform",
                "grade",
                "n_resolved",
                "wins",
                "losses",
                "win_rate",
                "win_rate_wilson_lb",
                "price_edge",
                "edge_hold",
                "edge_skill",
                "pnl",
                "volume",
                "cost",
                "roi",
                "last_category_trade_at"
              ],
              "properties": {
                "address": {
                  "type": "string",
                  "description": "Lowercase proxy wallet."
                },
                "cost": {
                  "type": ["number", "null"],
                  "description": "What the wallet paid, USD, for the settled markets pnl counts. null when any of them has no stored cost, never a partial sum."
                },
                "edge_hold": {
                  "description": "Why sort=edge sets aside an edge whose status is ranked. category_loss: the wallet's realized P&L in this sport or league is zero or below. record_incomplete: the wallet's stored sports and esports P&L runs more than 5% of its cost ahead of Polymarket's own figure, so settled losing markets are likely missing from its record. A held row keeps its price_edge and edge_skill and sorts after the ranked rows on sort=edge. null when nothing holds the edge, and always null unless price_edge.status is ranked.",
                  "anyOf": [
                    {
                      "type": "string",
                      "enum": ["category_loss", "record_incomplete"]
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "edge_skill": {
                  "type": ["number", "null"],
                  "description": "price_edge.edge pulled toward edge_average by the share of the record that is noise: a short record moves most of the way to the average, a long one keeps nearly all of its own edge. The value sort=edge orders by when edge_hold is null. null unless price_edge.status is ranked."
                },
                "grade": {
                  "description": "The wallet's all-time grade, S to F, the one every route serves. It is led by realized profit across all of the wallet's sports and esports markets, not this sport's or league's, so a wallet can lead a board on in-sport P&L and still grade F. Every letter is listed: the board ranks the in-sport record and does not filter on the grade. null when the wallet has no grade.",
                  "anyOf": [
                    {
                      "type": "string",
                      "enum": ["S", "A", "B", "C", "D", "F"]
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "id": {
                  "type": "string",
                  "description": "trd_0x..., the id the trader routes accept."
                },
                "last_category_trade_at": {
                  "type": ["string", "null"],
                  "format": "date-time",
                  "description": "The wallet's last trade on a settled market of $20 or more in this sport or league."
                },
                "losses": {
                  "type": "integer",
                  "description": "Markets n_resolved counts that settled at a realized loss. A market that broke even counts in neither wins nor losses."
                },
                "n_resolved": {
                  "type": "integer",
                  "description": "The wallet's settled markets of $20 or more in this sport or league; at least min_resolved."
                },
                "platform": {
                  "type": "string",
                  "enum": ["polymarket"],
                  "description": "Provider platform. Always polymarket."
                },
                "pnl": {
                  "type": ["number", "null"],
                  "description": "Realized P&L, USD, across the markets n_resolved counts: this sport or league only, not the wallet's whole record. The value sort=pnl orders by."
                },
                "price_edge": {
                  "description": "Edge over the price paid in this sport or league: how often the side the wallet bought won, minus the average price it paid. Probabilities throughout: edge 0.03 is 3 percentage points. A market bought on both sides counts by its shares. null when the wallet has no priced settled market here.",
                  "anyOf": [
                    {
                      "type": "object",
                      "required": [
                        "markets",
                        "hit_rate",
                        "avg_price",
                        "edge",
                        "edge_lower",
                        "status"
                      ],
                      "properties": {
                        "avg_price": {
                          "type": "number",
                          "description": "Mean entry price paid, 0-1."
                        },
                        "edge": {
                          "type": "number",
                          "description": "hit_rate minus avg_price, full precision, before any shrink. edge_skill is the shrunk value."
                        },
                        "edge_lower": {
                          "type": "number",
                          "description": "The low end of edge's 95% range: edge minus 1.96 times the square root of avg_price * (1 - avg_price) / markets. Not a sort key: sort=edge orders by edge_skill."
                        },
                        "hit_rate": {
                          "type": "number",
                          "description": "Share of those markets whose bought side won, 0-1. A market bought on both sides adds the winning side's share of the shares bought."
                        },
                        "markets": {
                          "type": "integer",
                          "description": "Settled markets of $20 or more in this sport or league at a known entry price that the edge is measured over."
                        },
                        "status": {
                          "type": "string",
                          "enum": ["ranked", "too_few_markets", "sample_mismatch"],
                          "description": "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 here. 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. Only a ranked edge with a null edge_hold orders on sort=edge."
                        }
                      }
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "rank": {
                  "type": "integer",
                  "description": "1-based position on this board under sort. A page of limit rows is the head of the board."
                },
                "roi": {
                  "type": ["number", "null"],
                  "description": "pnl / cost, a fraction: 0.12 is 12%. null when cost is null."
                },
                "username": {
                  "type": ["string", "null"],
                  "description": "The wallet's Polymarket username; null when it has none."
                },
                "volume": {
                  "type": ["number", "null"],
                  "description": "USD, measured as volume_scope says. On a sport board: the wallet's volume across all its sports and esports markets, the profile's Volume traded, not this sport's alone. null on every league board row: no per-league volume is stored."
                },
                "win_rate": {
                  "type": ["number", "null"],
                  "description": "wins / (wins + losses) in this sport or league, 0-1: 0.6 is 60%. null when no market was decided."
                },
                "win_rate_wilson_lb": {
                  "type": ["number", "null"],
                  "description": "The lower bound of the 95% Wilson interval on win_rate, 0-1: the value sort=win_rate orders by, so a short perfect record does not outrank a long strong one. null with win_rate."
                },
                "wins": {
                  "type": "integer",
                  "description": "Markets n_resolved counts that settled at a realized profit."
                }
              }
            }
          },
          "sort": {
            "type": "string",
            "enum": ["edge", "pnl", "win_rate"],
            "description": "The order rows are in. edge: by edge_skill, with every wallet whose edge is not ranked, or is held, after the ranked ones. pnl: by realized P&L in the sport or league. win_rate: by the Wilson lower bound of the win rate."
          },
          "sport": {
            "type": "string",
            "description": "The board's sport slug, for example soccer, basketball or esports. An alias in the path, such as nba or cs2, reads as its sport's slug."
          },
          "total_traders": {
            "type": "integer",
            "description": "Wallets with at least min_resolved settled markets in the sport or league and a trade, in any market, in the last 180 days: the field rows is the head of."
          },
          "volume_scope": {
            "type": "string",
            "enum": ["sports_and_esports"],
            "description": "What each row's volume measures. sports_and_esports: the wallet's volume across all its sports and esports markets, not this sport's or league's alone."
          }
        },
        "required": [
          "sport",
          "category",
          "league",
          "sort",
          "min_resolved",
          "limit",
          "total_traders",
          "edge_average",
          "volume_scope",
          "as_of",
          "rows"
        ]
      },
      "PickOfTheDayStats": {
        "type": "object",
        "properties": {
          "categories": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label",
                "picks",
                "wins",
                "losses",
                "void",
                "pending",
                "settled",
                "priced_decided",
                "small_sample",
                "staked_usd",
                "clv_measured"
              ],
              "properties": {
                "canonical_category": {
                  "type": "string"
                },
                "clv_avg_display": {
                  "type": "string"
                },
                "clv_avg_pct": {
                  "type": "number"
                },
                "clv_avg_pp": {
                  "type": "number"
                },
                "clv_avg_pp_display": {
                  "type": "string"
                },
                "clv_measured": {
                  "type": "integer"
                },
                "edge_display": {
                  "type": "string"
                },
                "edge_pp": {
                  "type": "number"
                },
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "priced_decided": {
                  "type": "integer"
                },
                "priced_in_display": {
                  "type": "string"
                },
                "priced_in_pct": {
                  "type": "number"
                },
                "roi_display": {
                  "type": "string"
                },
                "roi_pct": {
                  "type": "number"
                },
                "settled": {
                  "type": "integer"
                },
                "small_sample": {
                  "type": "boolean"
                },
                "staked_usd": {
                  "type": "number"
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "win_rate_display": {
                  "type": "string"
                },
                "win_rate_pct": {
                  "type": "number"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "days": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["date", "picks", "wins", "losses", "void", "pending"],
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "sweep": {
                  "type": "string",
                  "enum": ["win", "loss"]
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "hit_rate": {
            "$ref": "#/components/schemas/PickOfTheDayHitRate"
          },
          "market_expectations": {
            "type": "object",
            "required": ["as_of_date", "timezone", "price_basis", "windows"],
            "properties": {
              "as_of_date": {
                "type": "string",
                "format": "date"
              },
              "price_basis": {
                "type": "string"
              },
              "timezone": {
                "type": "string"
              },
              "windows": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "key",
                    "label",
                    "from_date",
                    "through_date",
                    "priced_decided",
                    "unpriced_decided",
                    "wins",
                    "expected_wins",
                    "expected_wins_display",
                    "units",
                    "units_display",
                    "wins_z",
                    "wins_z_display",
                    "units_z",
                    "units_z_display",
                    "clv_measured",
                    "clv_missing",
                    "clv_avg_pct",
                    "clv_avg_display",
                    "clv_avg_pp",
                    "clv_avg_pp_display",
                    "numeric_unavailable"
                  ],
                  "properties": {
                    "clv_avg_display": {
                      "type": ["string", "null"]
                    },
                    "clv_avg_pct": {
                      "type": ["number", "null"]
                    },
                    "clv_avg_pp": {
                      "type": ["number", "null"]
                    },
                    "clv_avg_pp_display": {
                      "type": ["string", "null"]
                    },
                    "clv_measured": {
                      "type": "integer"
                    },
                    "clv_missing": {
                      "type": "integer"
                    },
                    "expected_wins": {
                      "type": ["number", "null"]
                    },
                    "expected_wins_display": {
                      "type": ["string", "null"]
                    },
                    "from_date": {
                      "type": ["string", "null"],
                      "format": "date"
                    },
                    "key": {
                      "type": "string"
                    },
                    "label": {
                      "type": "string"
                    },
                    "numeric_unavailable": {
                      "type": "boolean"
                    },
                    "priced_decided": {
                      "type": "integer"
                    },
                    "through_date": {
                      "type": "string",
                      "format": "date"
                    },
                    "units": {
                      "type": ["number", "null"]
                    },
                    "units_display": {
                      "type": ["string", "null"]
                    },
                    "units_z": {
                      "type": ["number", "null"]
                    },
                    "units_z_display": {
                      "type": ["string", "null"]
                    },
                    "unpriced_decided": {
                      "type": "integer"
                    },
                    "wins": {
                      "type": "integer"
                    },
                    "wins_z": {
                      "type": ["number", "null"]
                    },
                    "wins_z_display": {
                      "type": ["string", "null"]
                    }
                  }
                }
              }
            }
          },
          "market_types": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label",
                "picks",
                "wins",
                "losses",
                "void",
                "pending",
                "settled",
                "priced_decided",
                "small_sample",
                "staked_usd",
                "clv_measured"
              ],
              "properties": {
                "canonical_category": {
                  "type": "string"
                },
                "clv_avg_display": {
                  "type": "string"
                },
                "clv_avg_pct": {
                  "type": "number"
                },
                "clv_avg_pp": {
                  "type": "number"
                },
                "clv_avg_pp_display": {
                  "type": "string"
                },
                "clv_measured": {
                  "type": "integer"
                },
                "edge_display": {
                  "type": "string"
                },
                "edge_pp": {
                  "type": "number"
                },
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "priced_decided": {
                  "type": "integer"
                },
                "priced_in_display": {
                  "type": "string"
                },
                "priced_in_pct": {
                  "type": "number"
                },
                "roi_display": {
                  "type": "string"
                },
                "roi_pct": {
                  "type": "number"
                },
                "settled": {
                  "type": "integer"
                },
                "small_sample": {
                  "type": "boolean"
                },
                "staked_usd": {
                  "type": "number"
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "win_rate_display": {
                  "type": "string"
                },
                "win_rate_pct": {
                  "type": "number"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "months": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label",
                "picks",
                "wins",
                "losses",
                "void",
                "pending",
                "settled",
                "priced_decided",
                "small_sample",
                "staked_usd",
                "clv_measured"
              ],
              "properties": {
                "canonical_category": {
                  "type": "string"
                },
                "clv_avg_display": {
                  "type": "string"
                },
                "clv_avg_pct": {
                  "type": "number"
                },
                "clv_avg_pp": {
                  "type": "number"
                },
                "clv_avg_pp_display": {
                  "type": "string"
                },
                "clv_measured": {
                  "type": "integer"
                },
                "edge_display": {
                  "type": "string"
                },
                "edge_pp": {
                  "type": "number"
                },
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "priced_decided": {
                  "type": "integer"
                },
                "priced_in_display": {
                  "type": "string"
                },
                "priced_in_pct": {
                  "type": "number"
                },
                "roi_display": {
                  "type": "string"
                },
                "roi_pct": {
                  "type": "number"
                },
                "settled": {
                  "type": "integer"
                },
                "small_sample": {
                  "type": "boolean"
                },
                "staked_usd": {
                  "type": "number"
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "win_rate_display": {
                  "type": "string"
                },
                "win_rate_pct": {
                  "type": "number"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "outcome_stats": {
            "type": "object",
            "required": ["drawdown", "rolling", "profit_factor", "concentration"],
            "properties": {
              "concentration": {
                "type": "object",
                "required": [
                  "valued_decided",
                  "positive_wins",
                  "removed_wins",
                  "target_wins",
                  "top_wins_share_pct",
                  "top_wins_share_display",
                  "remaining_valued_decided",
                  "roi_without_top_wins_pct",
                  "roi_without_top_wins_display"
                ],
                "properties": {
                  "positive_wins": {
                    "type": "integer"
                  },
                  "remaining_valued_decided": {
                    "type": "integer"
                  },
                  "removed_wins": {
                    "type": "integer"
                  },
                  "roi_without_top_wins_display": {
                    "type": ["string", "null"]
                  },
                  "roi_without_top_wins_pct": {
                    "type": ["number", "null"]
                  },
                  "target_wins": {
                    "type": "integer"
                  },
                  "top_wins_share_display": {
                    "type": ["string", "null"]
                  },
                  "top_wins_share_pct": {
                    "type": ["number", "null"]
                  },
                  "valued_decided": {
                    "type": "integer"
                  }
                }
              },
              "drawdown": {
                "type": "object",
                "required": [
                  "completed_days",
                  "excluded_days",
                  "from_date",
                  "through_date",
                  "max_drawdown_units",
                  "max_drawdown_display",
                  "current_drawdown_units",
                  "current_drawdown_display",
                  "days_below_peak",
                  "longest_days_below_peak",
                  "current_days_below_peak",
                  "longest_recovery_days",
                  "peak_date",
                  "peak_net_profit_usd"
                ],
                "properties": {
                  "completed_days": {
                    "type": "integer"
                  },
                  "current_days_below_peak": {
                    "type": ["integer", "null"]
                  },
                  "current_drawdown_display": {
                    "type": ["string", "null"]
                  },
                  "current_drawdown_units": {
                    "type": ["number", "null"]
                  },
                  "days_below_peak": {
                    "type": ["integer", "null"]
                  },
                  "excluded_days": {
                    "type": "integer"
                  },
                  "from_date": {
                    "type": ["string", "null"],
                    "format": "date"
                  },
                  "longest_days_below_peak": {
                    "type": ["integer", "null"]
                  },
                  "longest_recovery_days": {
                    "type": ["integer", "null"]
                  },
                  "max_drawdown_display": {
                    "type": ["string", "null"]
                  },
                  "max_drawdown_units": {
                    "type": ["number", "null"]
                  },
                  "peak_date": {
                    "type": ["string", "null"],
                    "format": "date"
                  },
                  "peak_net_profit_usd": {
                    "type": ["number", "null"]
                  },
                  "through_date": {
                    "type": ["string", "null"],
                    "format": "date"
                  }
                }
              },
              "profit_factor": {
                "type": "object",
                "required": [
                  "valued_decided",
                  "state",
                  "gross_profit_usd",
                  "gross_loss_usd",
                  "value",
                  "display"
                ],
                "properties": {
                  "display": {
                    "type": ["string", "null"]
                  },
                  "gross_loss_usd": {
                    "type": ["number", "null"]
                  },
                  "gross_profit_usd": {
                    "type": ["number", "null"]
                  },
                  "state": {
                    "type": "string",
                    "enum": ["empty", "measured", "no_losses", "numeric_unavailable"]
                  },
                  "value": {
                    "type": ["number", "null"]
                  },
                  "valued_decided": {
                    "type": "integer"
                  }
                }
              },
              "rolling": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "window_size",
                    "valued_decided",
                    "wins",
                    "losses",
                    "from_date",
                    "through_date",
                    "units",
                    "units_display",
                    "roi_pct",
                    "roi_display",
                    "win_rate_pct",
                    "win_rate_display"
                  ],
                  "properties": {
                    "from_date": {
                      "type": ["string", "null"],
                      "format": "date"
                    },
                    "losses": {
                      "type": "integer"
                    },
                    "roi_display": {
                      "type": ["string", "null"]
                    },
                    "roi_pct": {
                      "type": ["number", "null"]
                    },
                    "through_date": {
                      "type": ["string", "null"],
                      "format": "date"
                    },
                    "units": {
                      "type": ["number", "null"]
                    },
                    "units_display": {
                      "type": ["string", "null"]
                    },
                    "valued_decided": {
                      "type": "integer"
                    },
                    "win_rate_display": {
                      "type": ["string", "null"]
                    },
                    "win_rate_pct": {
                      "type": ["number", "null"]
                    },
                    "window_size": {
                      "type": "integer"
                    },
                    "wins": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "price_bands": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label",
                "picks",
                "wins",
                "losses",
                "void",
                "pending",
                "settled",
                "priced_decided",
                "small_sample",
                "staked_usd",
                "clv_measured"
              ],
              "properties": {
                "canonical_category": {
                  "type": "string"
                },
                "clv_avg_display": {
                  "type": "string"
                },
                "clv_avg_pct": {
                  "type": "number"
                },
                "clv_avg_pp": {
                  "type": "number"
                },
                "clv_avg_pp_display": {
                  "type": "string"
                },
                "clv_measured": {
                  "type": "integer"
                },
                "edge_display": {
                  "type": "string"
                },
                "edge_pp": {
                  "type": "number"
                },
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "priced_decided": {
                  "type": "integer"
                },
                "priced_in_display": {
                  "type": "string"
                },
                "priced_in_pct": {
                  "type": "number"
                },
                "roi_display": {
                  "type": "string"
                },
                "roi_pct": {
                  "type": "number"
                },
                "settled": {
                  "type": "integer"
                },
                "small_sample": {
                  "type": "boolean"
                },
                "staked_usd": {
                  "type": "number"
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "win_rate_display": {
                  "type": "string"
                },
                "win_rate_pct": {
                  "type": "number"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "records": {
            "type": "object",
            "required": ["sweeps"],
            "properties": {
              "best_day": {
                "type": "object",
                "required": [
                  "date",
                  "date_display",
                  "picks",
                  "wins",
                  "losses",
                  "net_profit_usd",
                  "net_profit_display"
                ],
                "properties": {
                  "date": {
                    "type": "string",
                    "format": "date"
                  },
                  "date_display": {
                    "type": "string"
                  },
                  "losses": {
                    "type": "integer"
                  },
                  "net_profit_display": {
                    "type": "string"
                  },
                  "net_profit_usd": {
                    "type": "number"
                  },
                  "picks": {
                    "type": "integer"
                  },
                  "wins": {
                    "type": "integer"
                  }
                }
              },
              "biggest_win": {
                "type": "object",
                "required": [
                  "date",
                  "date_display",
                  "matchup",
                  "category",
                  "net_profit_usd",
                  "net_profit_display"
                ],
                "properties": {
                  "category": {
                    "type": "string"
                  },
                  "date": {
                    "type": "string",
                    "format": "date"
                  },
                  "date_display": {
                    "type": "string"
                  },
                  "matchup": {
                    "type": "string"
                  },
                  "net_profit_display": {
                    "type": "string"
                  },
                  "net_profit_usd": {
                    "type": "number"
                  }
                }
              },
              "longest_losing_day_streak": {
                "type": "object",
                "required": [
                  "days",
                  "start_date",
                  "end_date",
                  "range_display",
                  "net_profit_usd",
                  "net_profit_display"
                ],
                "properties": {
                  "days": {
                    "type": "integer"
                  },
                  "end_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "net_profit_display": {
                    "type": "string"
                  },
                  "net_profit_usd": {
                    "type": "number"
                  },
                  "range_display": {
                    "type": "string"
                  },
                  "start_date": {
                    "type": "string",
                    "format": "date"
                  }
                }
              },
              "longest_winning_day_streak": {
                "type": "object",
                "required": [
                  "days",
                  "start_date",
                  "end_date",
                  "range_display",
                  "net_profit_usd",
                  "net_profit_display"
                ],
                "properties": {
                  "days": {
                    "type": "integer"
                  },
                  "end_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "net_profit_display": {
                    "type": "string"
                  },
                  "net_profit_usd": {
                    "type": "number"
                  },
                  "range_display": {
                    "type": "string"
                  },
                  "start_date": {
                    "type": "string",
                    "format": "date"
                  }
                }
              },
              "sweeps": {
                "type": "object",
                "required": ["min_decided", "clean_sweeps", "wipeouts"],
                "properties": {
                  "clean_sweeps": {
                    "type": "integer"
                  },
                  "latest_clean_sweep": {
                    "type": "object",
                    "required": ["date", "date_display", "wins", "losses"],
                    "properties": {
                      "date": {
                        "type": "string",
                        "format": "date"
                      },
                      "date_display": {
                        "type": "string"
                      },
                      "losses": {
                        "type": "integer"
                      },
                      "wins": {
                        "type": "integer"
                      }
                    }
                  },
                  "latest_wipeout": {
                    "type": "object",
                    "required": ["date", "date_display", "wins", "losses"],
                    "properties": {
                      "date": {
                        "type": "string",
                        "format": "date"
                      },
                      "date_display": {
                        "type": "string"
                      },
                      "losses": {
                        "type": "integer"
                      },
                      "wins": {
                        "type": "integer"
                      }
                    }
                  },
                  "min_decided": {
                    "type": "integer"
                  },
                  "wipeouts": {
                    "type": "integer"
                  }
                }
              },
              "winning_days": {
                "type": "object",
                "required": [
                  "winning",
                  "losing",
                  "flat",
                  "settled",
                  "winning_pct",
                  "winning_pct_display"
                ],
                "properties": {
                  "flat": {
                    "type": "integer"
                  },
                  "losing": {
                    "type": "integer"
                  },
                  "settled": {
                    "type": "integer"
                  },
                  "winning": {
                    "type": "integer"
                  },
                  "winning_pct": {
                    "type": "number"
                  },
                  "winning_pct_display": {
                    "type": "string"
                  }
                }
              },
              "worst_day": {
                "type": "object",
                "required": [
                  "date",
                  "date_display",
                  "picks",
                  "wins",
                  "losses",
                  "net_profit_usd",
                  "net_profit_display"
                ],
                "properties": {
                  "date": {
                    "type": "string",
                    "format": "date"
                  },
                  "date_display": {
                    "type": "string"
                  },
                  "losses": {
                    "type": "integer"
                  },
                  "net_profit_display": {
                    "type": "string"
                  },
                  "net_profit_usd": {
                    "type": "number"
                  },
                  "picks": {
                    "type": "integer"
                  },
                  "wins": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "sports": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label",
                "picks",
                "wins",
                "losses",
                "void",
                "pending",
                "settled",
                "priced_decided",
                "small_sample",
                "staked_usd",
                "clv_measured"
              ],
              "properties": {
                "canonical_category": {
                  "type": "string"
                },
                "clv_avg_display": {
                  "type": "string"
                },
                "clv_avg_pct": {
                  "type": "number"
                },
                "clv_avg_pp": {
                  "type": "number"
                },
                "clv_avg_pp_display": {
                  "type": "string"
                },
                "clv_measured": {
                  "type": "integer"
                },
                "edge_display": {
                  "type": "string"
                },
                "edge_pp": {
                  "type": "number"
                },
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "priced_decided": {
                  "type": "integer"
                },
                "priced_in_display": {
                  "type": "string"
                },
                "priced_in_pct": {
                  "type": "number"
                },
                "roi_display": {
                  "type": "string"
                },
                "roi_pct": {
                  "type": "number"
                },
                "settled": {
                  "type": "integer"
                },
                "small_sample": {
                  "type": "boolean"
                },
                "staked_usd": {
                  "type": "number"
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "win_rate_display": {
                  "type": "string"
                },
                "win_rate_pct": {
                  "type": "number"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "streaks": {
            "type": "object",
            "required": ["longest_win", "longest_loss"],
            "properties": {
              "current": {
                "type": "integer"
              },
              "current_day": {
                "type": "integer"
              },
              "current_day_display": {
                "type": "string"
              },
              "current_display": {
                "type": "string"
              },
              "longest_loss": {
                "type": "integer"
              },
              "longest_win": {
                "type": "integer"
              }
            }
          },
          "tiers": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label",
                "picks",
                "wins",
                "losses",
                "void",
                "pending",
                "settled",
                "priced_decided",
                "small_sample",
                "staked_usd",
                "clv_measured"
              ],
              "properties": {
                "canonical_category": {
                  "type": "string"
                },
                "clv_avg_display": {
                  "type": "string"
                },
                "clv_avg_pct": {
                  "type": "number"
                },
                "clv_avg_pp": {
                  "type": "number"
                },
                "clv_avg_pp_display": {
                  "type": "string"
                },
                "clv_measured": {
                  "type": "integer"
                },
                "edge_display": {
                  "type": "string"
                },
                "edge_pp": {
                  "type": "number"
                },
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "priced_decided": {
                  "type": "integer"
                },
                "priced_in_display": {
                  "type": "string"
                },
                "priced_in_pct": {
                  "type": "number"
                },
                "roi_display": {
                  "type": "string"
                },
                "roi_pct": {
                  "type": "number"
                },
                "settled": {
                  "type": "integer"
                },
                "small_sample": {
                  "type": "boolean"
                },
                "staked_usd": {
                  "type": "number"
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "win_rate_display": {
                  "type": "string"
                },
                "win_rate_pct": {
                  "type": "number"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "total_sides": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label",
                "picks",
                "wins",
                "losses",
                "void",
                "pending",
                "settled",
                "priced_decided",
                "small_sample",
                "staked_usd",
                "clv_measured"
              ],
              "properties": {
                "canonical_category": {
                  "type": "string"
                },
                "clv_avg_display": {
                  "type": "string"
                },
                "clv_avg_pct": {
                  "type": "number"
                },
                "clv_avg_pp": {
                  "type": "number"
                },
                "clv_avg_pp_display": {
                  "type": "string"
                },
                "clv_measured": {
                  "type": "integer"
                },
                "edge_display": {
                  "type": "string"
                },
                "edge_pp": {
                  "type": "number"
                },
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "priced_decided": {
                  "type": "integer"
                },
                "priced_in_display": {
                  "type": "string"
                },
                "priced_in_pct": {
                  "type": "number"
                },
                "roi_display": {
                  "type": "string"
                },
                "roi_pct": {
                  "type": "number"
                },
                "settled": {
                  "type": "integer"
                },
                "small_sample": {
                  "type": "boolean"
                },
                "staked_usd": {
                  "type": "number"
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "win_rate_display": {
                  "type": "string"
                },
                "win_rate_pct": {
                  "type": "number"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "voids": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["pick_id", "pick_date", "pick_rank"],
              "properties": {
                "backed_price": {
                  "type": "number"
                },
                "backed_side": {
                  "type": "string"
                },
                "category": {
                  "type": "string"
                },
                "matchup": {
                  "type": "string"
                },
                "pick_date": {
                  "type": "string",
                  "format": "date"
                },
                "pick_id": {
                  "type": "string"
                },
                "pick_rank": {
                  "type": "integer"
                }
              }
            }
          }
        },
        "required": [
          "voids",
          "hit_rate",
          "market_expectations",
          "outcome_stats",
          "days",
          "categories",
          "sports",
          "tiers",
          "months",
          "price_bands",
          "market_types",
          "total_sides",
          "streaks",
          "records"
        ]
      },
      "PickOfTheDayStatsSections": {
        "description": "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`.",
        "type": "object",
        "properties": {
          "categories": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label",
                "picks",
                "wins",
                "losses",
                "void",
                "pending",
                "settled",
                "priced_decided",
                "small_sample",
                "staked_usd",
                "clv_measured"
              ],
              "properties": {
                "canonical_category": {
                  "type": "string"
                },
                "clv_avg_display": {
                  "type": "string"
                },
                "clv_avg_pct": {
                  "type": "number"
                },
                "clv_avg_pp": {
                  "type": "number"
                },
                "clv_avg_pp_display": {
                  "type": "string"
                },
                "clv_measured": {
                  "type": "integer"
                },
                "edge_display": {
                  "type": "string"
                },
                "edge_pp": {
                  "type": "number"
                },
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "priced_decided": {
                  "type": "integer"
                },
                "priced_in_display": {
                  "type": "string"
                },
                "priced_in_pct": {
                  "type": "number"
                },
                "roi_display": {
                  "type": "string"
                },
                "roi_pct": {
                  "type": "number"
                },
                "settled": {
                  "type": "integer"
                },
                "small_sample": {
                  "type": "boolean"
                },
                "staked_usd": {
                  "type": "number"
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "win_rate_display": {
                  "type": "string"
                },
                "win_rate_pct": {
                  "type": "number"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "days": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["date", "picks", "wins", "losses", "void", "pending"],
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "sweep": {
                  "type": "string",
                  "enum": ["win", "loss"]
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "hit_rate": {
            "type": "object",
            "required": [
              "wins",
              "losses",
              "decided",
              "pct",
              "void",
              "pending",
              "stake_usd",
              "net_profit_usd",
              "staked_usd",
              "roi_pct",
              "net_profit_display",
              "roi_display",
              "win_rate_display",
              "clv_eligible",
              "clv_total",
              "clv_measured",
              "clv_applicable",
              "clv_not_applicable",
              "clv_pending",
              "clv_unavailable",
              "clv_state",
              "clv_beats_close",
              "clv_ties"
            ],
            "properties": {
              "clv_applicable": {
                "type": "integer"
              },
              "clv_avg_display": {
                "type": "string"
              },
              "clv_avg_pct": {
                "type": "number"
              },
              "clv_avg_pp": {
                "type": "number"
              },
              "clv_avg_pp_display": {
                "type": "string"
              },
              "clv_beats_close": {
                "type": "integer"
              },
              "clv_coverage_display": {
                "type": "string"
              },
              "clv_coverage_explanation": {
                "type": "string"
              },
              "clv_coverage_pct": {
                "type": "number"
              },
              "clv_eligible": {
                "type": "integer"
              },
              "clv_measured": {
                "type": "integer"
              },
              "clv_not_applicable": {
                "type": "integer"
              },
              "clv_pending": {
                "type": "integer"
              },
              "clv_state": {
                "type": "string"
              },
              "clv_ties": {
                "type": "integer"
              },
              "clv_total": {
                "type": "integer"
              },
              "clv_unavailable": {
                "type": "integer"
              },
              "decided": {
                "type": "integer"
              },
              "losses": {
                "type": "integer"
              },
              "net_profit_display": {
                "type": "string"
              },
              "net_profit_usd": {
                "type": "number"
              },
              "pct": {
                "type": "number"
              },
              "pending": {
                "type": "integer"
              },
              "roi_display": {
                "type": "string"
              },
              "roi_pct": {
                "type": "number"
              },
              "stake_usd": {
                "type": "number"
              },
              "staked_usd": {
                "type": "number"
              },
              "unit_score": {
                "type": "number"
              },
              "unit_score_display": {
                "type": "string"
              },
              "void": {
                "type": "integer"
              },
              "win_rate_display": {
                "type": "string"
              },
              "wins": {
                "type": "integer"
              }
            }
          },
          "market_expectations": {
            "type": "object",
            "required": ["as_of_date", "timezone", "price_basis", "windows"],
            "properties": {
              "as_of_date": {
                "type": "string",
                "format": "date"
              },
              "price_basis": {
                "type": "string"
              },
              "timezone": {
                "type": "string"
              },
              "windows": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "key",
                    "label",
                    "from_date",
                    "through_date",
                    "priced_decided",
                    "unpriced_decided",
                    "wins",
                    "expected_wins",
                    "expected_wins_display",
                    "units",
                    "units_display",
                    "wins_z",
                    "wins_z_display",
                    "units_z",
                    "units_z_display",
                    "clv_measured",
                    "clv_missing",
                    "clv_avg_pct",
                    "clv_avg_display",
                    "clv_avg_pp",
                    "clv_avg_pp_display",
                    "numeric_unavailable"
                  ],
                  "properties": {
                    "clv_avg_display": {
                      "type": ["string", "null"]
                    },
                    "clv_avg_pct": {
                      "type": ["number", "null"]
                    },
                    "clv_avg_pp": {
                      "type": ["number", "null"]
                    },
                    "clv_avg_pp_display": {
                      "type": ["string", "null"]
                    },
                    "clv_measured": {
                      "type": "integer"
                    },
                    "clv_missing": {
                      "type": "integer"
                    },
                    "expected_wins": {
                      "type": ["number", "null"]
                    },
                    "expected_wins_display": {
                      "type": ["string", "null"]
                    },
                    "from_date": {
                      "type": ["string", "null"],
                      "format": "date"
                    },
                    "key": {
                      "type": "string"
                    },
                    "label": {
                      "type": "string"
                    },
                    "numeric_unavailable": {
                      "type": "boolean"
                    },
                    "priced_decided": {
                      "type": "integer"
                    },
                    "through_date": {
                      "type": "string",
                      "format": "date"
                    },
                    "units": {
                      "type": ["number", "null"]
                    },
                    "units_display": {
                      "type": ["string", "null"]
                    },
                    "units_z": {
                      "type": ["number", "null"]
                    },
                    "units_z_display": {
                      "type": ["string", "null"]
                    },
                    "unpriced_decided": {
                      "type": "integer"
                    },
                    "wins": {
                      "type": "integer"
                    },
                    "wins_z": {
                      "type": ["number", "null"]
                    },
                    "wins_z_display": {
                      "type": ["string", "null"]
                    }
                  }
                }
              }
            }
          },
          "market_types": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label",
                "picks",
                "wins",
                "losses",
                "void",
                "pending",
                "settled",
                "priced_decided",
                "small_sample",
                "staked_usd",
                "clv_measured"
              ],
              "properties": {
                "canonical_category": {
                  "type": "string"
                },
                "clv_avg_display": {
                  "type": "string"
                },
                "clv_avg_pct": {
                  "type": "number"
                },
                "clv_avg_pp": {
                  "type": "number"
                },
                "clv_avg_pp_display": {
                  "type": "string"
                },
                "clv_measured": {
                  "type": "integer"
                },
                "edge_display": {
                  "type": "string"
                },
                "edge_pp": {
                  "type": "number"
                },
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "priced_decided": {
                  "type": "integer"
                },
                "priced_in_display": {
                  "type": "string"
                },
                "priced_in_pct": {
                  "type": "number"
                },
                "roi_display": {
                  "type": "string"
                },
                "roi_pct": {
                  "type": "number"
                },
                "settled": {
                  "type": "integer"
                },
                "small_sample": {
                  "type": "boolean"
                },
                "staked_usd": {
                  "type": "number"
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "win_rate_display": {
                  "type": "string"
                },
                "win_rate_pct": {
                  "type": "number"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "months": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label",
                "picks",
                "wins",
                "losses",
                "void",
                "pending",
                "settled",
                "priced_decided",
                "small_sample",
                "staked_usd",
                "clv_measured"
              ],
              "properties": {
                "canonical_category": {
                  "type": "string"
                },
                "clv_avg_display": {
                  "type": "string"
                },
                "clv_avg_pct": {
                  "type": "number"
                },
                "clv_avg_pp": {
                  "type": "number"
                },
                "clv_avg_pp_display": {
                  "type": "string"
                },
                "clv_measured": {
                  "type": "integer"
                },
                "edge_display": {
                  "type": "string"
                },
                "edge_pp": {
                  "type": "number"
                },
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "priced_decided": {
                  "type": "integer"
                },
                "priced_in_display": {
                  "type": "string"
                },
                "priced_in_pct": {
                  "type": "number"
                },
                "roi_display": {
                  "type": "string"
                },
                "roi_pct": {
                  "type": "number"
                },
                "settled": {
                  "type": "integer"
                },
                "small_sample": {
                  "type": "boolean"
                },
                "staked_usd": {
                  "type": "number"
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "win_rate_display": {
                  "type": "string"
                },
                "win_rate_pct": {
                  "type": "number"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "outcome_stats": {
            "type": "object",
            "required": ["drawdown", "rolling", "profit_factor", "concentration"],
            "properties": {
              "concentration": {
                "type": "object",
                "required": [
                  "valued_decided",
                  "positive_wins",
                  "removed_wins",
                  "target_wins",
                  "top_wins_share_pct",
                  "top_wins_share_display",
                  "remaining_valued_decided",
                  "roi_without_top_wins_pct",
                  "roi_without_top_wins_display"
                ],
                "properties": {
                  "positive_wins": {
                    "type": "integer"
                  },
                  "remaining_valued_decided": {
                    "type": "integer"
                  },
                  "removed_wins": {
                    "type": "integer"
                  },
                  "roi_without_top_wins_display": {
                    "type": ["string", "null"]
                  },
                  "roi_without_top_wins_pct": {
                    "type": ["number", "null"]
                  },
                  "target_wins": {
                    "type": "integer"
                  },
                  "top_wins_share_display": {
                    "type": ["string", "null"]
                  },
                  "top_wins_share_pct": {
                    "type": ["number", "null"]
                  },
                  "valued_decided": {
                    "type": "integer"
                  }
                }
              },
              "drawdown": {
                "type": "object",
                "required": [
                  "completed_days",
                  "excluded_days",
                  "from_date",
                  "through_date",
                  "max_drawdown_units",
                  "max_drawdown_display",
                  "current_drawdown_units",
                  "current_drawdown_display",
                  "days_below_peak",
                  "longest_days_below_peak",
                  "current_days_below_peak",
                  "longest_recovery_days",
                  "peak_date",
                  "peak_net_profit_usd"
                ],
                "properties": {
                  "completed_days": {
                    "type": "integer"
                  },
                  "current_days_below_peak": {
                    "type": ["integer", "null"]
                  },
                  "current_drawdown_display": {
                    "type": ["string", "null"]
                  },
                  "current_drawdown_units": {
                    "type": ["number", "null"]
                  },
                  "days_below_peak": {
                    "type": ["integer", "null"]
                  },
                  "excluded_days": {
                    "type": "integer"
                  },
                  "from_date": {
                    "type": ["string", "null"],
                    "format": "date"
                  },
                  "longest_days_below_peak": {
                    "type": ["integer", "null"]
                  },
                  "longest_recovery_days": {
                    "type": ["integer", "null"]
                  },
                  "max_drawdown_display": {
                    "type": ["string", "null"]
                  },
                  "max_drawdown_units": {
                    "type": ["number", "null"]
                  },
                  "peak_date": {
                    "type": ["string", "null"],
                    "format": "date"
                  },
                  "peak_net_profit_usd": {
                    "type": ["number", "null"]
                  },
                  "through_date": {
                    "type": ["string", "null"],
                    "format": "date"
                  }
                }
              },
              "profit_factor": {
                "type": "object",
                "required": [
                  "valued_decided",
                  "state",
                  "gross_profit_usd",
                  "gross_loss_usd",
                  "value",
                  "display"
                ],
                "properties": {
                  "display": {
                    "type": ["string", "null"]
                  },
                  "gross_loss_usd": {
                    "type": ["number", "null"]
                  },
                  "gross_profit_usd": {
                    "type": ["number", "null"]
                  },
                  "state": {
                    "type": "string",
                    "enum": ["empty", "measured", "no_losses", "numeric_unavailable"]
                  },
                  "value": {
                    "type": ["number", "null"]
                  },
                  "valued_decided": {
                    "type": "integer"
                  }
                }
              },
              "rolling": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "window_size",
                    "valued_decided",
                    "wins",
                    "losses",
                    "from_date",
                    "through_date",
                    "units",
                    "units_display",
                    "roi_pct",
                    "roi_display",
                    "win_rate_pct",
                    "win_rate_display"
                  ],
                  "properties": {
                    "from_date": {
                      "type": ["string", "null"],
                      "format": "date"
                    },
                    "losses": {
                      "type": "integer"
                    },
                    "roi_display": {
                      "type": ["string", "null"]
                    },
                    "roi_pct": {
                      "type": ["number", "null"]
                    },
                    "through_date": {
                      "type": ["string", "null"],
                      "format": "date"
                    },
                    "units": {
                      "type": ["number", "null"]
                    },
                    "units_display": {
                      "type": ["string", "null"]
                    },
                    "valued_decided": {
                      "type": "integer"
                    },
                    "win_rate_display": {
                      "type": ["string", "null"]
                    },
                    "win_rate_pct": {
                      "type": ["number", "null"]
                    },
                    "window_size": {
                      "type": "integer"
                    },
                    "wins": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "price_bands": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label",
                "picks",
                "wins",
                "losses",
                "void",
                "pending",
                "settled",
                "priced_decided",
                "small_sample",
                "staked_usd",
                "clv_measured"
              ],
              "properties": {
                "canonical_category": {
                  "type": "string"
                },
                "clv_avg_display": {
                  "type": "string"
                },
                "clv_avg_pct": {
                  "type": "number"
                },
                "clv_avg_pp": {
                  "type": "number"
                },
                "clv_avg_pp_display": {
                  "type": "string"
                },
                "clv_measured": {
                  "type": "integer"
                },
                "edge_display": {
                  "type": "string"
                },
                "edge_pp": {
                  "type": "number"
                },
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "priced_decided": {
                  "type": "integer"
                },
                "priced_in_display": {
                  "type": "string"
                },
                "priced_in_pct": {
                  "type": "number"
                },
                "roi_display": {
                  "type": "string"
                },
                "roi_pct": {
                  "type": "number"
                },
                "settled": {
                  "type": "integer"
                },
                "small_sample": {
                  "type": "boolean"
                },
                "staked_usd": {
                  "type": "number"
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "win_rate_display": {
                  "type": "string"
                },
                "win_rate_pct": {
                  "type": "number"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "records": {
            "type": "object",
            "required": ["sweeps"],
            "properties": {
              "best_day": {
                "type": "object",
                "required": [
                  "date",
                  "date_display",
                  "picks",
                  "wins",
                  "losses",
                  "net_profit_usd",
                  "net_profit_display"
                ],
                "properties": {
                  "date": {
                    "type": "string",
                    "format": "date"
                  },
                  "date_display": {
                    "type": "string"
                  },
                  "losses": {
                    "type": "integer"
                  },
                  "net_profit_display": {
                    "type": "string"
                  },
                  "net_profit_usd": {
                    "type": "number"
                  },
                  "picks": {
                    "type": "integer"
                  },
                  "wins": {
                    "type": "integer"
                  }
                }
              },
              "biggest_win": {
                "type": "object",
                "required": [
                  "date",
                  "date_display",
                  "matchup",
                  "category",
                  "net_profit_usd",
                  "net_profit_display"
                ],
                "properties": {
                  "category": {
                    "type": "string"
                  },
                  "date": {
                    "type": "string",
                    "format": "date"
                  },
                  "date_display": {
                    "type": "string"
                  },
                  "matchup": {
                    "type": "string"
                  },
                  "net_profit_display": {
                    "type": "string"
                  },
                  "net_profit_usd": {
                    "type": "number"
                  }
                }
              },
              "longest_losing_day_streak": {
                "type": "object",
                "required": [
                  "days",
                  "start_date",
                  "end_date",
                  "range_display",
                  "net_profit_usd",
                  "net_profit_display"
                ],
                "properties": {
                  "days": {
                    "type": "integer"
                  },
                  "end_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "net_profit_display": {
                    "type": "string"
                  },
                  "net_profit_usd": {
                    "type": "number"
                  },
                  "range_display": {
                    "type": "string"
                  },
                  "start_date": {
                    "type": "string",
                    "format": "date"
                  }
                }
              },
              "longest_winning_day_streak": {
                "type": "object",
                "required": [
                  "days",
                  "start_date",
                  "end_date",
                  "range_display",
                  "net_profit_usd",
                  "net_profit_display"
                ],
                "properties": {
                  "days": {
                    "type": "integer"
                  },
                  "end_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "net_profit_display": {
                    "type": "string"
                  },
                  "net_profit_usd": {
                    "type": "number"
                  },
                  "range_display": {
                    "type": "string"
                  },
                  "start_date": {
                    "type": "string",
                    "format": "date"
                  }
                }
              },
              "sweeps": {
                "type": "object",
                "required": ["min_decided", "clean_sweeps", "wipeouts"],
                "properties": {
                  "clean_sweeps": {
                    "type": "integer"
                  },
                  "latest_clean_sweep": {
                    "type": "object",
                    "required": ["date", "date_display", "wins", "losses"],
                    "properties": {
                      "date": {
                        "type": "string",
                        "format": "date"
                      },
                      "date_display": {
                        "type": "string"
                      },
                      "losses": {
                        "type": "integer"
                      },
                      "wins": {
                        "type": "integer"
                      }
                    }
                  },
                  "latest_wipeout": {
                    "type": "object",
                    "required": ["date", "date_display", "wins", "losses"],
                    "properties": {
                      "date": {
                        "type": "string",
                        "format": "date"
                      },
                      "date_display": {
                        "type": "string"
                      },
                      "losses": {
                        "type": "integer"
                      },
                      "wins": {
                        "type": "integer"
                      }
                    }
                  },
                  "min_decided": {
                    "type": "integer"
                  },
                  "wipeouts": {
                    "type": "integer"
                  }
                }
              },
              "winning_days": {
                "type": "object",
                "required": [
                  "winning",
                  "losing",
                  "flat",
                  "settled",
                  "winning_pct",
                  "winning_pct_display"
                ],
                "properties": {
                  "flat": {
                    "type": "integer"
                  },
                  "losing": {
                    "type": "integer"
                  },
                  "settled": {
                    "type": "integer"
                  },
                  "winning": {
                    "type": "integer"
                  },
                  "winning_pct": {
                    "type": "number"
                  },
                  "winning_pct_display": {
                    "type": "string"
                  }
                }
              },
              "worst_day": {
                "type": "object",
                "required": [
                  "date",
                  "date_display",
                  "picks",
                  "wins",
                  "losses",
                  "net_profit_usd",
                  "net_profit_display"
                ],
                "properties": {
                  "date": {
                    "type": "string",
                    "format": "date"
                  },
                  "date_display": {
                    "type": "string"
                  },
                  "losses": {
                    "type": "integer"
                  },
                  "net_profit_display": {
                    "type": "string"
                  },
                  "net_profit_usd": {
                    "type": "number"
                  },
                  "picks": {
                    "type": "integer"
                  },
                  "wins": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "sections": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "series": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["date", "net_profit_usd", "hit_rate_pct"],
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "hit_rate_pct": {
                  "type": "number"
                },
                "net_profit_usd": {
                  "type": "number"
                }
              }
            }
          },
          "sports": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label",
                "picks",
                "wins",
                "losses",
                "void",
                "pending",
                "settled",
                "priced_decided",
                "small_sample",
                "staked_usd",
                "clv_measured"
              ],
              "properties": {
                "canonical_category": {
                  "type": "string"
                },
                "clv_avg_display": {
                  "type": "string"
                },
                "clv_avg_pct": {
                  "type": "number"
                },
                "clv_avg_pp": {
                  "type": "number"
                },
                "clv_avg_pp_display": {
                  "type": "string"
                },
                "clv_measured": {
                  "type": "integer"
                },
                "edge_display": {
                  "type": "string"
                },
                "edge_pp": {
                  "type": "number"
                },
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "priced_decided": {
                  "type": "integer"
                },
                "priced_in_display": {
                  "type": "string"
                },
                "priced_in_pct": {
                  "type": "number"
                },
                "roi_display": {
                  "type": "string"
                },
                "roi_pct": {
                  "type": "number"
                },
                "settled": {
                  "type": "integer"
                },
                "small_sample": {
                  "type": "boolean"
                },
                "staked_usd": {
                  "type": "number"
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "win_rate_display": {
                  "type": "string"
                },
                "win_rate_pct": {
                  "type": "number"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "streaks": {
            "type": "object",
            "required": ["longest_win", "longest_loss"],
            "properties": {
              "current": {
                "type": "integer"
              },
              "current_day": {
                "type": "integer"
              },
              "current_day_display": {
                "type": "string"
              },
              "current_display": {
                "type": "string"
              },
              "longest_loss": {
                "type": "integer"
              },
              "longest_win": {
                "type": "integer"
              }
            }
          },
          "tiers": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label",
                "picks",
                "wins",
                "losses",
                "void",
                "pending",
                "settled",
                "priced_decided",
                "small_sample",
                "staked_usd",
                "clv_measured"
              ],
              "properties": {
                "canonical_category": {
                  "type": "string"
                },
                "clv_avg_display": {
                  "type": "string"
                },
                "clv_avg_pct": {
                  "type": "number"
                },
                "clv_avg_pp": {
                  "type": "number"
                },
                "clv_avg_pp_display": {
                  "type": "string"
                },
                "clv_measured": {
                  "type": "integer"
                },
                "edge_display": {
                  "type": "string"
                },
                "edge_pp": {
                  "type": "number"
                },
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "priced_decided": {
                  "type": "integer"
                },
                "priced_in_display": {
                  "type": "string"
                },
                "priced_in_pct": {
                  "type": "number"
                },
                "roi_display": {
                  "type": "string"
                },
                "roi_pct": {
                  "type": "number"
                },
                "settled": {
                  "type": "integer"
                },
                "small_sample": {
                  "type": "boolean"
                },
                "staked_usd": {
                  "type": "number"
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "win_rate_display": {
                  "type": "string"
                },
                "win_rate_pct": {
                  "type": "number"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "total_sides": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label",
                "picks",
                "wins",
                "losses",
                "void",
                "pending",
                "settled",
                "priced_decided",
                "small_sample",
                "staked_usd",
                "clv_measured"
              ],
              "properties": {
                "canonical_category": {
                  "type": "string"
                },
                "clv_avg_display": {
                  "type": "string"
                },
                "clv_avg_pct": {
                  "type": "number"
                },
                "clv_avg_pp": {
                  "type": "number"
                },
                "clv_avg_pp_display": {
                  "type": "string"
                },
                "clv_measured": {
                  "type": "integer"
                },
                "edge_display": {
                  "type": "string"
                },
                "edge_pp": {
                  "type": "number"
                },
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "losses": {
                  "type": "integer"
                },
                "net_profit_display": {
                  "type": "string"
                },
                "net_profit_usd": {
                  "type": "number"
                },
                "pending": {
                  "type": "integer"
                },
                "picks": {
                  "type": "integer"
                },
                "priced_decided": {
                  "type": "integer"
                },
                "priced_in_display": {
                  "type": "string"
                },
                "priced_in_pct": {
                  "type": "number"
                },
                "roi_display": {
                  "type": "string"
                },
                "roi_pct": {
                  "type": "number"
                },
                "settled": {
                  "type": "integer"
                },
                "small_sample": {
                  "type": "boolean"
                },
                "staked_usd": {
                  "type": "number"
                },
                "unit_score": {
                  "type": "number"
                },
                "unit_score_display": {
                  "type": "string"
                },
                "void": {
                  "type": "integer"
                },
                "win_rate_display": {
                  "type": "string"
                },
                "win_rate_pct": {
                  "type": "number"
                },
                "wins": {
                  "type": "integer"
                }
              }
            }
          },
          "view": {
            "type": "string"
          },
          "voids": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["pick_id", "pick_date", "pick_rank"],
              "properties": {
                "backed_price": {
                  "type": "number"
                },
                "backed_side": {
                  "type": "string"
                },
                "category": {
                  "type": "string"
                },
                "matchup": {
                  "type": "string"
                },
                "pick_date": {
                  "type": "string",
                  "format": "date"
                },
                "pick_id": {
                  "type": "string"
                },
                "pick_rank": {
                  "type": "integer"
                }
              }
            }
          }
        },
        "required": ["view", "sections"]
      },
      "ResolutionReport": {
        "type": "object",
        "properties": {
          "accuracy": {
            "type": ["number", "null"]
          },
          "all_wallets_accuracy": {
            "type": ["number", "null"]
          },
          "all_wallets_right": {
            "type": ["integer", "null"]
          },
          "all_wallets_wrong": {
            "type": ["integer", "null"]
          },
          "date": {
            "type": ["string", "null"]
          },
          "generated_at": {
            "type": ["string", "null"]
          },
          "grade_basis": {
            "anyOf": [
              {
                "type": "string",
                "enum": ["at_resolution", "current"]
              },
              {
                "type": "null"
              }
            ]
          },
          "market_scope": {
            "type": "string",
            "enum": ["all_markets", "sports_and_esports"]
          },
          "markets": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "condition_id",
                "title",
                "outcome_yes",
                "outcome_no",
                "event_slug",
                "category",
                "report_at",
                "time_basis",
                "winning_outcome",
                "smart_consensus",
                "smart_right",
                "all_wallets_right",
                "confidence",
                "smart_trader_count",
                "total_smart_pnl",
                "weighted_yes",
                "weighted_no",
                "out_of_product_scope",
                "traders"
              ],
              "properties": {
                "all_wallets_right": {
                  "type": ["boolean", "null"]
                },
                "category": {
                  "type": ["string", "null"]
                },
                "condition_id": {
                  "type": ["string", "null"]
                },
                "confidence": {
                  "type": ["number", "null"]
                },
                "event_slug": {
                  "type": ["string", "null"]
                },
                "out_of_product_scope": {
                  "type": "boolean"
                },
                "outcome_no": {
                  "type": ["string", "null"]
                },
                "outcome_yes": {
                  "type": ["string", "null"]
                },
                "report_at": {
                  "type": "string",
                  "format": "date-time"
                },
                "smart_consensus": {
                  "type": ["string", "null"]
                },
                "smart_right": {
                  "type": ["boolean", "null"]
                },
                "smart_trader_count": {
                  "type": ["integer", "null"]
                },
                "time_basis": {
                  "type": "string",
                  "enum": ["polymarket_gamma_closed_time", "observed_resolution"]
                },
                "title": {
                  "type": ["string", "null"]
                },
                "total_smart_pnl": {
                  "type": ["number", "null"]
                },
                "traders": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "address",
                      "username",
                      "grade",
                      "side",
                      "correct",
                      "pnl",
                      "cost",
                      "last_traded_at"
                    ],
                    "properties": {
                      "address": {
                        "type": ["string", "null"]
                      },
                      "correct": {
                        "type": ["boolean", "null"]
                      },
                      "cost": {
                        "type": ["number", "null"]
                      },
                      "grade": {
                        "anyOf": [
                          {
                            "type": "string",
                            "enum": ["S", "A", "B", "C", "D", "F"]
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "last_traded_at": {
                        "type": ["string", "null"],
                        "format": "date-time"
                      },
                      "pnl": {
                        "type": ["number", "null"]
                      },
                      "side": {
                        "type": ["string", "null"]
                      },
                      "username": {
                        "type": ["string", "null"]
                      }
                    }
                  }
                },
                "weighted_no": {
                  "type": ["number", "null"]
                },
                "weighted_yes": {
                  "type": ["number", "null"]
                },
                "winning_outcome": {
                  "type": ["integer", "null"]
                }
              }
            }
          },
          "markets_without_smart_positions": {
            "type": ["integer", "null"]
          },
          "no_consensus": {
            "type": ["integer", "null"]
          },
          "positions_grade_unknown": {
            "type": ["integer", "null"]
          },
          "positions_without_side": {
            "type": ["integer", "null"]
          },
          "smart_money_right": {
            "type": ["integer", "null"]
          },
          "smart_money_wrong": {
            "type": ["integer", "null"]
          },
          "source_updates_pending": {
            "type": "boolean"
          },
          "time_basis_counts": {
            "anyOf": [
              {
                "type": "object",
                "required": ["polymarket_gamma_closed_time", "observed_resolution"],
                "properties": {
                  "observed_resolution": {
                    "type": "integer"
                  },
                  "polymarket_gamma_closed_time": {
                    "type": "integer"
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "total_resolved": {
            "type": ["integer", "null"]
          },
          "total_smart_pnl": {
            "type": ["number", "null"]
          },
          "with_smart_positions": {
            "type": ["integer", "null"]
          }
        },
        "required": [
          "date",
          "market_scope",
          "grade_basis",
          "total_resolved",
          "with_smart_positions",
          "smart_money_right",
          "smart_money_wrong",
          "no_consensus",
          "accuracy",
          "all_wallets_right",
          "all_wallets_wrong",
          "all_wallets_accuracy",
          "total_smart_pnl",
          "markets_without_smart_positions",
          "positions_grade_unknown",
          "positions_without_side",
          "time_basis_counts",
          "generated_at",
          "source_updates_pending"
        ]
      },
      "WebhookEventType": {
        "type": "string",
        "enum": [
          "large_trade_inserted_v2",
          "large_trades_inserted",
          "whale_trades_inserted",
          "live_sports_updated",
          "trader_synced",
          "whale_trader_synced",
          "large_positions_updated",
          "wallet_grade_changed",
          "suspicious_trade_flagged",
          "insider_radar_flag_raised",
          "sharp_money_flow_detected",
          "smart_money_flow_detected",
          "export_job_ready",
          "export_job_failed",
          "export_job_expired",
          "export_job_cancelled",
          "market_price_moved"
        ]
      },
      "PriceMoveSubscriptionFilters": {
        "type": "object",
        "additionalProperties": false,
        "description": "Settings for market_price_moved: required when event_types includes it, refused (400) when it does not. A PATCH without it keeps the stored settings; removing the event clears them. A subscription receives at most one delivery per market per window: the one level step whose (previous_level_cents, level_cents] holds min_move_cents.",
        "required": ["min_move_cents", "window_seconds", "phase", "require_concurrent_sharp_flow"],
        "properties": {
          "min_move_cents": {
            "type": "integer",
            "minimum": 2,
            "maximum": 50,
            "description": "Move threshold in whole cents of outcome 0's midpoint."
          },
          "window_seconds": {
            "type": "integer",
            "enum": [60, 120, 300, 900],
            "description": "The window the move is measured over."
          },
          "condition_id": {
            "type": "string",
            "description": "One market only. Raw or mkt_-prefixed."
          },
          "event_slug": {
            "type": "string",
            "description": "One Polymarket event (game) only."
          },
          "league": {
            "type": "array",
            "minItems": 1,
            "maxItems": 32,
            "items": {
              "type": "string"
            },
            "description": "Event slug league prefixes such as nba or epl, matched case-insensitively; any one matches."
          },
          "phase": {
            "type": "string",
            "enum": ["any", "pre_game", "in_play"],
            "default": "any",
            "description": "Game phase when the move was detected. any includes unknown."
          },
          "require_concurrent_sharp_flow": {
            "type": "boolean",
            "default": false,
            "description": "Deliver only moves with concurrent_sharp_flow.detected true."
          },
          "min_book_usd_within_2c": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10000000,
            "description": "Deliver only moves whose book_depth_within_2c is known and holds at least this many USD on each side. A move with book_depth_within_2c null does not match."
          }
        }
      },
      "LargeTradeSubscriptionFilters": {
        "type": "object",
        "additionalProperties": false,
        "description": "All present fields narrow large_trade_inserted_v2 delivery. min_grade reads the payload's grade, observed at publication; min_grade_at_trade reads its grade_at_trade, the grade when the trade filled. Send one of the two, not both (400). An empty object matches every large trade.",
        "properties": {
          "condition_id": {
            "type": "string",
            "description": "Raw provider condition ID or mkt_-prefixed market ID."
          },
          "wallet": {
            "type": "string",
            "pattern": "^0x[a-fA-F0-9]{40}$",
            "description": "Polymarket wallet address; matching is case-insensitive."
          },
          "min_grade": {
            "type": "string",
            "enum": ["S", "A", "B", "C", "D", "F"],
            "description": "S is best; ungraded trades do not match. Reads the wallet's grade when the trade was published, which for a backfilled trade can be hours after the fill."
          },
          "min_grade_at_trade": {
            "type": "string",
            "enum": ["S", "A", "B", "C", "D", "F"],
            "description": "S is best. Reads grade_at_trade, the grade the trader held when the trade filled; only a trade whose grade_at_trade_status is graded matches. The same basis as min_grade_at_trade on GET /api/v1/large-trades and GET /api/v1/stream."
          },
          "min_size_usd": {
            "type": "string",
            "pattern": "^[0-9]+(\\.[0-9]{1,6})?$",
            "description": "Positive USD notional as an exact decimal string."
          }
        }
      },
      "WebhookStatus": {
        "type": "string",
        "enum": ["pending_verification", "active", "disabled"]
      },
      "WebhookRetryPolicy": {
        "type": "object",
        "required": [
          "max_attempts",
          "terminal_status",
          "retry_horizon_seconds",
          "disable_after_consecutive_failures"
        ],
        "properties": {
          "max_attempts": {
            "type": "integer",
            "const": 8
          },
          "terminal_status": {
            "type": "string",
            "const": "dead_letter"
          },
          "retry_horizon_seconds": {
            "type": "integer",
            "const": 7380,
            "description": "Total wait from a delivery's first failed attempt to its last retry: 60, 120, 240, 480, 960, 1920 and 3600 seconds. A delivery still failing after that is dead_letter."
          },
          "disable_after_consecutive_failures": {
            "type": "integer",
            "const": 8,
            "description": "Consecutive failed attempts, across all of this endpoint's deliveries, after which the endpoint is disabled and its queued deliveries are dead-lettered. Any successful attempt resets the count."
          }
        }
      },
      "WebhookVerification": {
        "type": "object",
        "required": ["token", "expires_at"],
        "properties": {
          "token": {
            "type": "string",
            "description": "One-time verification token returned only on create or URL change. Pass it to POST /api/v1/webhooks/{id}/verify, which activates the endpoint only when the destination also answers the signed webhook.verification challenge with a 2xx."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WebhookEventDescriptor": {
        "type": "object",
        "description": "Self-describing entry in the webhook event catalog: the event type a subscriber lists in event_types, when it fires, the data payload shape, and whether it currently fires (active) or is reserved (dormant, subscribable but not yet delivered). Pro-only event types (large_trades_inserted, whale_trades_inserted, wallet_grade_changed, suspicious_trade_flagged, insider_radar_flag_raised, sharp_money_flow_detected, smart_money_flow_detected) only deliver to API keys on an active Pro subscription. Export lifecycle event types (export_job_ready, export_job_failed, export_job_expired, export_job_cancelled) are owner-scoped to the API-key account that created the export and contain no download URL; use the authorized export status/download routes. Some entries are two spellings of one event: large_trades_inserted and whale_trades_inserted, trader_synced and whale_trader_synced, suspicious_trade_flagged and insider_radar_flag_raised, sharp_money_flow_detected and smart_money_flow_detected. Either spelling subscribes, and an endpoint receives deliveries under the spelling it registered. The deprecated spellings (whale_trades_inserted, whale_trader_synced, insider_radar_flag_raised, smart_money_flow_detected) reach their sunset on 2027-02-01 (#29352); register the canonical spelling.",
        "required": ["id", "description", "payload_shape", "status"],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/WebhookEventType"
          },
          "description": {
            "type": "string",
            "description": "One-line description of when the event fires."
          },
          "payload_shape": {
            "type": "string",
            "description": "Short description of the data payload object's shape."
          },
          "status": {
            "type": "string",
            "enum": ["active", "dormant"],
            "description": "active: the event has a firing producer callsite. dormant: advertised and subscribable, but does not yet enqueue any delivery."
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "description": "Owner-scoped view of one webhook delivery attempt. Deliberately omits the request body and the endpoint signing secret: a delivery log never re-exposes the payload or any secret material.",
        "required": [
          "id",
          "object",
          "event_id",
          "event_type",
          "status",
          "attempt_count",
          "next_attempt_at",
          "retry_schedule_reason",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "object": {
            "type": "string",
            "const": "webhook_delivery"
          },
          "event_id": {
            "type": "string",
            "description": "Stable event id for this delivery; identical across retries of the same logical event."
          },
          "event_type": {
            "$ref": "#/components/schemas/WebhookEventType"
          },
          "status": {
            "type": "string",
            "description": "Delivery lifecycle state (e.g. pending, delivered, dead_letter)."
          },
          "attempt_count": {
            "type": "integer",
            "description": "Number of delivery attempts made so far."
          },
          "last_response_status": {
            "type": "integer",
            "description": "HTTP status code of the most recent delivery attempt. Omitted until a response (or transport error) has been recorded."
          },
          "last_error": {
            "type": "string",
            "description": "Short description of the most recent delivery failure. Omitted when the last attempt succeeded or none has failed."
          },
          "delivered_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the delivery was first accepted by the destination. Omitted until a delivery succeeds."
          },
          "next_attempt_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When the next delivery attempt is due, for a delivery whose status is pending or retry. null while an attempt is in flight (processing) and once the delivery is terminal (delivered or dead_letter)."
          },
          "retry_schedule_reason": {
            "type": ["string", "null"],
            "enum": [
              "receiver_retry_after",
              "transient_failure",
              "permanent_or_auth_failure",
              "manual_redelivery",
              "configuration_changed",
              null
            ],
            "description": "Why next_attempt_at was scheduled: receiver_retry_after for an accepted Retry-After on a 408, 429, or 5xx response; transient_failure for a network or ordinary transient retry; permanent_or_auth_failure for another non-2xx response; manual_redelivery or configuration_changed for those queue actions. null while an attempt is in flight or once the delivery is terminal."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WebhookSecretRotation": {
        "type": "object",
        "required": ["status", "overlap_expires_at"],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["idle", "pending", "overlap"],
            "description": "idle when no staged rotation exists, pending after prepare, and overlap after activate while both signing secrets are accepted."
          },
          "overlap_expires_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When the previous signing secret stops being emitted and accepted. null outside the overlap phase."
          }
        }
      },
      "WebhookEndpoint": {
        "type": "object",
        "required": [
          "id",
          "object",
          "name",
          "url",
          "event_types",
          "trade_filters",
          "price_move_filters",
          "status",
          "verified_at",
          "verification_token_expires_at",
          "failure_count",
          "created_at",
          "updated_at",
          "retry_policy",
          "secret_rotation"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "object": {
            "type": "string",
            "const": "webhook"
          },
          "name": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "event_types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEventType"
            }
          },
          "trade_filters": {
            "$ref": "#/components/schemas/LargeTradeSubscriptionFilters"
          },
          "price_move_filters": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PriceMoveSubscriptionFilters"
              },
              {
                "type": "null"
              }
            ],
            "description": "The market_price_moved settings; null unless that event is subscribed."
          },
          "status": {
            "$ref": "#/components/schemas/WebhookStatus"
          },
          "verified_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "verification_token_expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "failure_count": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "retry_policy": {
            "$ref": "#/components/schemas/WebhookRetryPolicy"
          },
          "secret_rotation": {
            "$ref": "#/components/schemas/WebhookSecretRotation"
          },
          "signing_secret": {
            "type": "string",
            "description": "Returned only on create, immediate rotate-secret, staged rotate-secret/prepare, or staged rotate-secret/activate. Never returned by list, get, update, delete, verify, or retire."
          },
          "verification": {
            "$ref": "#/components/schemas/WebhookVerification"
          }
        }
      },
      "CreateWebhookRequest": {
        "type": "object",
        "required": ["name", "url", "event_types"],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Public HTTPS callback URL on the default port 443. Local, private, and internal targets are rejected, as is any explicit port other than 443 and any URL carrying credentials. Each user's URLs are unique after normalizing HTTPS scheme/host case, trailing DNS dots and port 443; path/query case is preserved. Pending verification and PATCH-disabled endpoints still reserve their stored URL. The destination must answer the signed webhook.verification challenge with a 2xx before POST /api/v1/webhooks/{id}/verify can activate the endpoint."
          },
          "event_types": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/WebhookEventType"
            }
          },
          "trade_filters": {
            "$ref": "#/components/schemas/LargeTradeSubscriptionFilters"
          },
          "price_move_filters": {
            "$ref": "#/components/schemas/PriceMoveSubscriptionFilters"
          }
        }
      },
      "UpdateWebhookRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Replacement public HTTPS callback URL on the default port 443, validated and checked for uniqueness exactly like the create url. HTTPS scheme/host case, trailing DNS dots and port 443 normalize; path/query case is preserved. Changing it resets status to pending_verification and returns a new verification token; the new destination must pass the verification challenge before deliveries resume."
          },
          "event_types": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/WebhookEventType"
            }
          },
          "trade_filters": {
            "$ref": "#/components/schemas/LargeTradeSubscriptionFilters"
          },
          "price_move_filters": {
            "$ref": "#/components/schemas/PriceMoveSubscriptionFilters"
          },
          "enabled": {
            "type": "boolean"
          }
        }
      },
      "VerifyWebhookRequest": {
        "type": "object",
        "required": ["verification_token"],
        "properties": {
          "verification_token": {
            "type": "string",
            "description": "The one-time token returned on create or on a url change. It is necessary but not sufficient: the destination must also answer the signed webhook.verification challenge with a 2xx."
          }
        }
      },
      "Candle": {
        "type": "object",
        "description": "One bucketed OHLC price candle. Prices are in provider [0, 1] units, truncated to 4 decimals at the rendering edge.",
        "required": ["t", "o", "h", "l", "c"],
        "properties": {
          "t": {
            "type": "integer",
            "format": "int64",
            "description": "Bucket-start unix epoch (seconds): UTC midnight for 1d, the ISO-week Monday's UTC midnight for 1w."
          },
          "o": {
            "type": "number",
            "description": "Open price in provider [0, 1] units (first observed point in the bucket)."
          },
          "h": {
            "type": "number",
            "description": "High price in provider [0, 1] units (max observed in the bucket)."
          },
          "l": {
            "type": "number",
            "description": "Low price in provider [0, 1] units (min observed in the bucket)."
          },
          "c": {
            "type": "number",
            "description": "Close price in provider [0, 1] units (last observed point in the bucket)."
          }
        }
      },
      "OutcomeCandles": {
        "type": "object",
        "description": "One outcome token's bucketed candle series.",
        "required": ["token_id", "outcome", "candles"],
        "properties": {
          "token_id": {
            "type": "string",
            "description": "Provider CLOB token id the candles were read for."
          },
          "outcome": {
            "type": "string",
            "description": "Canonical side label.",
            "enum": ["YES", "NO"]
          },
          "candles": {
            "type": "array",
            "description": "OHLC candles for this outcome token, ascending by bucket start.",
            "items": {
              "$ref": "#/components/schemas/Candle"
            }
          }
        }
      },
      "MarketCandles": {
        "type": "object",
        "description": "Provider-first bucketed OHLC price candles for a market's outcome tokens, derived from our stored copy of the Polymarket CLOB prices-history series (covers open and resolved markets).",
        "required": ["condition_id", "resolution", "outcomes"],
        "properties": {
          "condition_id": {
            "type": "string",
            "description": "Market condition id the candles were read for."
          },
          "resolution": {
            "type": "string",
            "description": "Bucketing granularity that produced these candles.",
            "enum": ["1d", "1w"]
          },
          "outcomes": {
            "type": "array",
            "description": "One entry per present provider token (YES first, then NO); empty when no tokens have been fetched yet.",
            "items": {
              "$ref": "#/components/schemas/OutcomeCandles"
            }
          }
        }
      },
      "MarketClose": {
        "type": "object",
        "properties": {
          "anchor_stale": {
            "type": ["boolean", "null"],
            "description": "true when game_start_time has moved more than lookback_seconds from close_anchor_at since capture; large trades on the market then carry no CLV. null without a stored row."
          },
          "basis_version": {
            "type": ["string", "null"],
            "description": "Provider response contract version the value was read under."
          },
          "captured_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When the close was stored. Bookkeeping only."
          },
          "close_anchor_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "The instant the close was measured at: the kickoff when it was captured. Write-once; null when no close row is stored."
          },
          "close_anchor_source": {
            "type": ["string", "null"],
            "description": "The field that supplied close_anchor_at, markets.game_start_time."
          },
          "condition_id": {
            "type": "string",
            "description": "Polymarket condition id."
          },
          "game_start_time": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "The market's kickoff as stored now."
          },
          "lookback_seconds": {
            "type": ["integer", "null"],
            "description": "How far before the anchor the admitted bucket may start: 21600 (6 hours)."
          },
          "observation_window_seconds": {
            "type": ["integer", "null"],
            "description": "Bucket width: 60 (minute grain) or 3600 (hour grain, for a market read more than about six days after kickoff)."
          },
          "observed_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Start of the provider bucket the close is. The bucket ends at observed_at + observation_window_seconds, at or before close_anchor_at."
          },
          "outcomes": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "outcome_index",
                "outcome",
                "token_id",
                "close_price",
                "derived_from_yes"
              ],
              "properties": {
                "close_price": {
                  "type": "number",
                  "description": "Closing price, 0 to 1, at full stored precision."
                },
                "derived_from_yes": {
                  "type": "boolean",
                  "description": "true on the NO leg: 1 minus the stored YES price, never a second read."
                },
                "outcome": {
                  "type": ["string", "null"],
                  "description": "The outcome's label."
                },
                "outcome_index": {
                  "type": "integer",
                  "description": "0 is the YES leg, 1 the NO leg."
                },
                "token_id": {
                  "type": ["string", "null"],
                  "description": "CLOB token id of the outcome."
                }
              }
            },
            "description": "YES then NO when status is measured; empty otherwise."
          },
          "price_source": {
            "type": ["string", "null"],
            "description": "Provider endpoint and grain, e.g. polymarket_data_v2_prices_history@minute-window-v1."
          },
          "status": {
            "type": "string",
            "enum": ["measured", "pending", "unavailable"],
            "description": "measured: outcomes carries the close. pending: no close is stored yet and the capture will still read the market. unavailable: no close will be served; see unavailable_reason."
          },
          "unavailable_reason": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "no_observation_in_lookback",
                  "provider_empty_window",
                  "provider_invalid_contract",
                  "capture_window_closed",
                  "no_game_start_time",
                  "not_one_sided_resolution",
                  "not_captured",
                  "close_token_mismatch",
                  "anchor_stale",
                  "outcome_unknown"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Set exactly when status is unavailable. no_observation_in_lookback, provider_empty_window, provider_invalid_contract and capture_window_closed are the capture's own stored refusals; no_game_start_time: the market has no kickoff time; not_one_sided_resolution: it resolved to neither side; not_captured: the capture does not read it (no tracked buy before resolution, or kickoff over 30 days ago); close_token_mismatch: the close was read on a different YES token than the market carries now."
          }
        },
        "required": [
          "condition_id",
          "status",
          "unavailable_reason",
          "game_start_time",
          "close_anchor_at",
          "close_anchor_source",
          "anchor_stale",
          "lookback_seconds",
          "observed_at",
          "observation_window_seconds",
          "price_source",
          "basis_version",
          "captured_at",
          "outcomes"
        ],
        "description": "A market's stored closing line (#32517): Polymarket's price-history value for the last minute bucket ending at or before kickoff, read once after settlement and never recomputed."
      },
      "MarketWalletsInOut": {
        "type": "object",
        "description": "One market's net buyers and net sellers over a 24h or 7d window, as the market page's wallets in/out panel shows a Pro viewer.",
        "required": [
          "condition_id",
          "window",
          "window_start",
          "window_end",
          "summary",
          "net_buyers",
          "net_sellers"
        ],
        "properties": {
          "condition_id": {
            "type": "string",
            "description": "The market's raw provider condition id."
          },
          "window": {
            "type": "string",
            "description": "The window the nets are summed over: 24h or 7d."
          },
          "window_start": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "The window's inclusive start; null only when the bounds are unknown."
          },
          "window_end": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "The window's inclusive end, the read's clock; null only when the bounds are unknown."
          },
          "summary": {
            "type": "object",
            "description": "Totals over every wallet that traded the market in the window, not only the listed 50.",
            "required": ["wallets_in", "wallets_out", "net_usd"],
            "properties": {
              "wallets_in": {
                "type": "integer",
                "description": "Wallets with a positive net in the window."
              },
              "wallets_out": {
                "type": "integer",
                "description": "Wallets with a negative net in the window."
              },
              "net_usd": {
                "type": "number",
                "description": "The sum of every wallet's net, in USD. A fully rotated wallet nets zero and is on neither side."
              }
            }
          },
          "net_buyers": {
            "type": "array",
            "description": "Wallets whose net is positive, largest first, at most 25.",
            "items": {
              "type": "object",
              "description": "One wallet's net in the window.",
              "required": [
                "address",
                "display_name",
                "grade",
                "net_usd",
                "trades",
                "last_traded_at"
              ],
              "properties": {
                "address": {
                  "type": "string",
                  "description": "Lowercase proxy wallet."
                },
                "display_name": {
                  "type": "string",
                  "description": "The name the site shows: the 0xinsider username, else the shortened address."
                },
                "grade": {
                  "anyOf": [
                    {
                      "type": "string",
                      "enum": ["S", "A", "B", "C", "D", "F"]
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Today's grade; null for an ungraded or untracked wallet."
                },
                "net_usd": {
                  "type": "number",
                  "description": "Buys minus sells in the window, both outcomes, in USD: the matched notional, fees excluded."
                },
                "trades": {
                  "type": "integer",
                  "description": "Fills in the window."
                },
                "last_traded_at": {
                  "type": ["string", "null"],
                  "format": "date-time",
                  "description": "The wallet's newest trade on any market, at or before window_end; null when unknown."
                }
              }
            }
          },
          "net_sellers": {
            "type": "array",
            "description": "Wallets whose net is negative, most negative first, at most 25.",
            "items": {
              "type": "object",
              "description": "One wallet's net in the window.",
              "required": [
                "address",
                "display_name",
                "grade",
                "net_usd",
                "trades",
                "last_traded_at"
              ],
              "properties": {
                "address": {
                  "type": "string",
                  "description": "Lowercase proxy wallet."
                },
                "display_name": {
                  "type": "string",
                  "description": "The name the site shows: the 0xinsider username, else the shortened address."
                },
                "grade": {
                  "anyOf": [
                    {
                      "type": "string",
                      "enum": ["S", "A", "B", "C", "D", "F"]
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Today's grade; null for an ungraded or untracked wallet."
                },
                "net_usd": {
                  "type": "number",
                  "description": "Buys minus sells in the window, both outcomes, in USD: the matched notional, fees excluded."
                },
                "trades": {
                  "type": "integer",
                  "description": "Fills in the window."
                },
                "last_traded_at": {
                  "type": ["string", "null"],
                  "format": "date-time",
                  "description": "The wallet's newest trade on any market, at or before window_end; null when unknown."
                }
              }
            }
          }
        }
      },
      "Game": {
        "type": "object",
        "description": "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.",
        "required": [
          "object",
          "event_slug",
          "status",
          "competitors",
          "draw_offered",
          "markets",
          "freshness",
          "coverage",
          "url"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "game"
          },
          "event_slug": {
            "type": "string",
            "description": "The game's identity, for example mlb-mil-cin-2026-06-22. The same key the live_sports_updated webhook pulse carries and the same key /api/v1/games/{event_slug} takes."
          },
          "game_id": {
            "type": "string",
            "description": "The provider's Gamma gameId, as a string. Omitted when the canonical owner has no single value for this slug: the provider stamps one gameId across an event's derivative siblings, so an ambiguous read is reported as unknown rather than guessed."
          },
          "sport": {
            "type": "string",
            "description": "The canonical sport bucket, for example Soccer or Table Tennis. Omitted when neither the board scope nor the provider category names one."
          },
          "league": {
            "type": "string",
            "description": "The league tag, for example nfl or epl. Omitted for a sport served as one whole bucket with no league scope."
          },
          "title": {
            "type": "string",
            "description": "The provider's event title. Omitted when the provider sent none."
          },
          "scheduled_at": {
            "type": "string",
            "format": "date-time",
            "description": "Kickoff in UTC, as the provider supplied it. Omitted when the provider published none; coverage.schedule then reads unavailable."
          },
          "status": {
            "$ref": "#/components/schemas/GameStatus"
          },
          "competitors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GameCompetitor"
            },
            "description": "Both sides, in the provider's own order. That order states no home or away: Polymarket lists the away team first in US leagues and the home team first in soccer. Read a market's side for home and away. Empty when the provider identified neither side."
          },
          "series_format": {
            "type": "string",
            "description": "The esports series length, for example Bo3. Omitted for everything else."
          },
          "draw_offered": {
            "type": "boolean",
            "description": "Whether this read includes a market classified as paying on a draw, including soccer's independent 1X2 draw leg. Read this instead of assuming a two-outcome moneyline."
          },
          "markets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GameMarket"
            },
            "description": "The game's winner markets the sports board binds to its sides (the moneyline, or a soccer game's three 1X2 legs), ordered by condition_id. Spreads, totals, period lines and props are on GET /api/v1/games/{event_slug}/markets."
          },
          "freshness": {
            "$ref": "#/components/schemas/GameFreshness"
          },
          "coverage": {
            "$ref": "#/components/schemas/GameCoverage"
          },
          "url": {
            "type": "string",
            "description": "The game's page on 0xinsider."
          },
          "sharp_money": {
            "$ref": "#/components/schemas/GameSharpMoney"
          },
          "volume": {
            "$ref": "#/components/schemas/GameVolume",
            "description": "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."
          },
          "tournament": {
            "$ref": "#/components/schemas/GameTournament",
            "description": "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."
          }
        }
      },
      "GameTournament": {
        "type": "object",
        "description": "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.",
        "required": [
          "label",
          "tour",
          "edition_year",
          "starts_on",
          "ends_on",
          "source_urls",
          "checked_on"
        ],
        "properties": {
          "label": {
            "type": "string",
            "description": "The provider competition label that selected this edition, verbatim, for example \"Erste Bank Open, Qualification\"."
          },
          "tour": {
            "type": "string",
            "enum": ["atp", "wta", "itf"],
            "description": "The edition's tour."
          },
          "draw": {
            "type": "string",
            "enum": ["main", "qualification"],
            "description": "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."
          },
          "tier": {
            "type": "string",
            "description": "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."
          },
          "location": {
            "$ref": "#/components/schemas/GameTournamentLocation",
            "description": "The verified venue city and country. Omitted when no official page states it."
          },
          "timezone": {
            "type": "string",
            "description": "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."
          },
          "edition_year": {
            "type": "integer",
            "description": "The year of the edition."
          },
          "starts_on": {
            "type": "string",
            "format": "date",
            "description": "The edition's first official day, inclusive (YYYY-MM-DD). A qualifying match can be played up to two days before it."
          },
          "ends_on": {
            "type": "string",
            "format": "date",
            "description": "The edition's last official day, inclusive (YYYY-MM-DD)."
          },
          "source_urls": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            },
            "description": "The official tournament, tour, federation or time-zone pages the facts were taken from."
          },
          "checked_on": {
            "type": "string",
            "format": "date",
            "description": "When those pages were checked: a catalogue verification date, not a score or price clock."
          }
        }
      },
      "GameTournamentLocation": {
        "type": "object",
        "description": "A verified tournament venue.",
        "required": ["city", "country", "country_code"],
        "properties": {
          "city": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "country_code": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2, for example \"IT\"."
          }
        }
      },
      "GameVolume": {
        "type": "object",
        "description": "A game's traded volume as Polymarket reports it, read by the sports board with no request-time provider call. A one-side taker share count, the number Polymarket's own pages print behind a dollar sign, not the cash that changed hands.",
        "required": ["value", "source", "fresh_for_seconds"],
        "properties": {
          "value": {
            "type": "number",
            "description": "The volume at full precision, in unit."
          },
          "unit": {
            "type": "string",
            "enum": ["taker_shares"],
            "description": "taker_shares: cumulative one-side taker volume in shares. One share pays $1 at settlement, so this is not cash traded. Omitted only on a figure observed before units were recorded; never assume cash."
          },
          "basis": {
            "type": "string",
            "enum": ["game_lines", "event_total"],
            "description": "game_lines: the game volume Polymarket's game page states, summed over the game's own lines. event_total: the whole event's volume, stated when no game volume was readable. The two can differ in either direction. Omitted when the basis is unknown."
          },
          "source": {
            "type": "string",
            "enum": ["polymarket_data", "gamma"],
            "description": "The Polymarket API the figure was read from: polymarket_data (the Data API's live volume) or gamma (the Gamma API)."
          },
          "observed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When 0xinsider read the figure from the provider, never a provider-authored timestamp. Omitted when no read time is held for it."
          },
          "fresh_for_seconds": {
            "type": "integer",
            "minimum": 0,
            "description": "How long after observed_at 0xinsider treats the figure as current: 60 or 300 by source and basis, or 3600 for an older figure kept because a later read of the same total was lower or missing (a cumulative volume never falls)."
          }
        }
      },
      "GameSharpMoney": {
        "type": "object",
        "description": "Event-level sharp money for one game. Every aggregate field is null unless status is computed; null means unknown, never zero.",
        "properties": {
          "allocation": {
            "anyOf": [
              {
                "type": "string",
                "enum": ["exact", "degraded"]
              },
              {
                "type": "null"
              }
            ]
          },
          "computed_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "event_slug": {
            "type": "string"
          },
          "holders_partial": {
            "type": ["boolean", "null"]
          },
          "lifecycle": {
            "anyOf": [
              {
                "type": "string",
                "enum": ["live", "settled", "indeterminate"]
              },
              {
                "type": "null"
              }
            ]
          },
          "money_as_of": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "object": {
            "type": "string"
          },
          "outcomes": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["side", "label", "usd", "pct", "is_leader", "wallets"],
              "properties": {
                "is_leader": {
                  "type": "boolean"
                },
                "label": {
                  "type": "string"
                },
                "pct": {
                  "type": "integer"
                },
                "side": {
                  "type": ["string", "null"],
                  "enum": ["home", "draw", "away", null],
                  "description": "The side the provider designates this outcome's team: home or away, by Polymarket's own home/away designation (teams[].ordering), never the outcome's place in this list; draw for a 1X2 draw. null when the provider designates neither team home or away; never inferred from order."
                },
                "usd": {
                  "type": "number"
                },
                "wallets": {
                  "type": "object",
                  "required": ["s", "a", "b"],
                  "properties": {
                    "a": {
                      "type": "integer"
                    },
                    "b": {
                      "type": "integer"
                    },
                    "s": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "status": {
            "type": "string",
            "enum": ["computed", "not_computed", "unavailable"]
          },
          "total_usd": {
            "type": ["number", "null"]
          },
          "trader_count": {
            "type": ["integer", "null"]
          },
          "unallocated_usd": {
            "type": ["number", "null"]
          },
          "verdict": {
            "anyOf": [
              {
                "oneOf": [
                  {
                    "type": "object",
                    "required": ["kind"],
                    "properties": {
                      "kind": {
                        "type": "string",
                        "const": "no_sharp_money"
                      }
                    }
                  },
                  {
                    "type": "object",
                    "required": ["kind", "label"],
                    "properties": {
                      "kind": {
                        "type": "string",
                        "const": "all_on"
                      },
                      "label": {
                        "type": "string"
                      }
                    }
                  },
                  {
                    "type": "object",
                    "required": ["kind"],
                    "properties": {
                      "kind": {
                        "type": "string",
                        "const": "split"
                      }
                    }
                  },
                  {
                    "type": "object",
                    "required": ["kind", "label", "pct"],
                    "properties": {
                      "kind": {
                        "type": "string",
                        "const": "leans"
                      },
                      "label": {
                        "type": "string"
                      },
                      "pct": {
                        "type": "integer"
                      }
                    }
                  },
                  {
                    "type": "object",
                    "required": ["kind"],
                    "properties": {
                      "kind": {
                        "type": "string",
                        "const": "unavailable"
                      }
                    }
                  },
                  {
                    "type": "object",
                    "required": ["kind", "label", "divergence_pts"],
                    "properties": {
                      "divergence_pts": {
                        "type": "integer"
                      },
                      "kind": {
                        "type": "string",
                        "const": "leans_over_price"
                      },
                      "label": {
                        "type": "string"
                      }
                    }
                  },
                  {
                    "type": "object",
                    "required": ["kind"],
                    "properties": {
                      "kind": {
                        "type": "string",
                        "const": "no_clear_lean"
                      }
                    }
                  },
                  {
                    "type": "object",
                    "required": ["kind"],
                    "properties": {
                      "kind": {
                        "type": "string",
                        "const": "withheld"
                      }
                    }
                  }
                ]
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "object",
          "event_slug",
          "status",
          "lifecycle",
          "verdict",
          "allocation",
          "total_usd",
          "unallocated_usd",
          "trader_count",
          "holders_partial",
          "outcomes",
          "computed_at",
          "money_as_of"
        ]
      },
      "GameStatus": {
        "type": "object",
        "description": "Where the game is in its own life, as the provider reports it. A postponement, a cancellation and a suspension each keep their own state, so a client can tell a game that will be played later from one that never will be.",
        "required": ["state", "ended", "ended_at", "ended_at_source"],
        "properties": {
          "state": {
            "type": "string",
            "enum": [
              "scheduled",
              "live",
              "paused",
              "ended",
              "postponed",
              "cancelled",
              "suspended",
              "delayed",
              "unknown"
            ],
            "description": "scheduled: kickoff is ahead, or the provider still lists the game open and neither in play nor ended. With no live-score frame a game stays scheduled past its kickoff until the provider says otherwise. live: the provider reports it in play. paused: halftime or a provider-reported break. ended: the provider reported a final, an award or a forfeit. postponed, cancelled, suspended, delayed: the provider's own verdict, kept distinct. A tennis match that the provider still lists in play, with no live score feed and no change of period or score for 3 hours, also reads suspended. unknown: no provider state reached this read. A kickoff in the past is never read as live on its own."
          },
          "match_status": {
            "type": "string",
            "enum": [
              "scheduled",
              "in_progress",
              "halftime",
              "penalty_shootout",
              "delayed",
              "suspended",
              "final",
              "final_overtime",
              "final_shootout",
              "awarded",
              "forfeit",
              "not_necessary",
              "postponed",
              "cancelled",
              "unknown"
            ],
            "description": "The provider status folded onto one vocabulary across leagues. unknown means the provider sent a value this API has no meaning for; provider_status keeps that value verbatim. Omitted when no live-score frame carries a status, as for a listed game no live-score feed has reported yet."
          },
          "provider_status": {
            "type": "string",
            "description": "The live-score feed's status string, verbatim. Omitted when no live-score frame carries one. This API never puts a label of its own here, such as Scheduled for a listed game."
          },
          "period": {
            "type": "string",
            "description": "The provider's period label, for example Q3, End Q2 or T5. Omitted when the provider sent none."
          },
          "clock": {
            "type": "string",
            "description": "The game clock as the provider spells it, never reformatted. Omitted when the provider sent none."
          },
          "live": {
            "type": "boolean",
            "description": "Whether the game is in play. It is the provider's own in-play flag, except that three cases read false: a game the provider reports suspended (period SUS), a game rescheduled to a later kickoff, and a tennis match that the provider still lists in play with no live score feed and no change of period or score for 3 hours. Omitted when no live-score frame exists, which is not the same as false."
          },
          "ended": {
            "type": "boolean",
            "description": "Whether the game is over. Always present."
          },
          "ended_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When the game ended (RFC 3339 UTC), as first observed. Always present. It is null unless state is ended and an end was observed. It is never inferred from the kickoff, the clock or the market's resolution. Null on an ended game means the end time is unknown, and games that ended before this field shipped carry null. ended_at_source names who observed it."
          },
          "ended_at_source": {
            "anyOf": [
              {
                "type": "string",
                "enum": ["sports_ws", "gamma_finished"]
              },
              {
                "type": "null"
              }
            ],
            "description": "Who observed ended_at. Always present, and null exactly when ended_at is null. sports_ws: the first Polymarket Sports WebSocket frame that reported the game final, at the time it was received. gamma_finished: for a game no such frame ended, Polymarket's own event finish time, served only when it is earlier than the market's resolution and never for a fight card (MMA, boxing)."
          }
        }
      },
      "GameCompetitor": {
        "type": "object",
        "description": "One side of the game.",
        "required": ["name"],
        "properties": {
          "name": {
            "type": "string",
            "description": "The team as its moneyline outcome names it, the same before, during and after the game (Jaguars, Penn). Where no outcome names the team, for example a soccer game's Yes/No win markets, the provider's full name (FC Bayern München). To identify a team, prefer provider_id."
          },
          "provider_id": {
            "type": "string",
            "description": "The provider's league-scoped competitor id, as a string. Omitted when the provider has not identified this side; coverage.competitors then reads labels."
          },
          "logo": {
            "type": "string",
            "description": "Provider crest or logo URL. Omitted when there is none."
          },
          "score": {
            "type": "string",
            "description": "The provider's score for this side, verbatim. A string because the provider sends one: a set score, a map score and a run total are not all integers. Omitted when no live-score frame carries a score."
          },
          "record": {
            "type": "string",
            "description": "The provider's season record for this side, for example 12-4. Omitted when the provider sent none."
          }
        }
      },
      "GameTrade": {
        "type": "object",
        "description": "One fill in a game, as the game page's activity list shows it.",
        "required": [
          "id",
          "traded_at",
          "side",
          "outcome",
          "outcome_index",
          "price",
          "shares",
          "size_usd",
          "point",
          "trader",
          "market"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable fill identity: {transaction_hash}:{token_id}:{wallet}:{shares}. Deduplicate on it across polls."
          },
          "traded_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the fill happened, to the second."
          },
          "side": {
            "type": "string",
            "enum": ["BUY", "SELL"],
            "description": "The provider's side of the fill."
          },
          "outcome": {
            "type": ["string", "null"],
            "description": "The traded outcome's label; null when the provider named none."
          },
          "outcome_index": {
            "type": ["integer", "null"],
            "description": "0 for the first (Yes) outcome token, 1 for the second (No); null when the provider did not say."
          },
          "price": {
            "type": "number",
            "description": "Fill price, 0 to 1."
          },
          "shares": {
            "type": "number",
            "description": "Shares filled."
          },
          "size_usd": {
            "type": "number",
            "description": "USDC notional of the fill."
          },
          "point": {
            "type": ["number", "null"],
            "description": "The signed handicap the fill's side carries on a spread line, for example -1.5 or 1.5; null off spreads."
          },
          "trader": {
            "type": "object",
            "required": ["address", "display_name", "grade"],
            "properties": {
              "address": {
                "type": "string",
                "description": "Lowercase proxy wallet."
              },
              "display_name": {
                "type": "string",
                "description": "The name the site shows: the 0xinsider username, else the provider's name or pseudonym, else the shortened address."
              },
              "grade": {
                "type": ["string", "null"],
                "enum": ["S", "A", "B", "C", "D", "F", null],
                "description": "The trader's grade today; null for an ungraded or untracked wallet."
              }
            }
          },
          "market": {
            "type": "object",
            "required": ["id", "condition_id", "title", "slug", "line_label"],
            "properties": {
              "id": {
                "type": "string",
                "description": "The market's v1 id, mkt_ plus the condition_id."
              },
              "condition_id": {
                "type": "string",
                "description": "The raw provider condition_id."
              },
              "title": {
                "type": ["string", "null"],
                "description": "The market's question."
              },
              "slug": {
                "type": ["string", "null"],
                "description": "The market's page slug."
              },
              "line_label": {
                "type": ["string", "null"],
                "description": "The market's name within the game, for example Draw, O/U 2.5, First to Score: CD Guadalajara, Game 2: Any Player Quadra Kill."
              }
            }
          }
        }
      },
      "GameMarketPriceCompetitor": {
        "type": "object",
        "description": "One competitor-bound provider moneyline price. No YES/NO inference is required.",
        "required": ["label", "price", "price_provenance"],
        "properties": {
          "provider_id": {
            "type": "integer",
            "format": "int64",
            "description": "The provider competitor id when identity is available."
          },
          "label": {
            "type": "string",
            "description": "The provider competitor label."
          },
          "price": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Unrounded provider price in [0, 1]."
          },
          "price_provenance": {
            "type": "string",
            "enum": ["gamma_outcome_prices", "clob_display"],
            "description": "Which provider price observation supplies this leg."
          }
        }
      },
      "GameMarketPriceBindingProvenance": {
        "type": "string",
        "enum": ["provider_ids", "exact_labels", "containment_labels", "elimination"],
        "description": "How the existing sports-board writer bound prices to competitors."
      },
      "GameMarketPricePaired": {
        "type": "object",
        "description": "A validated provider moneyline pair bound to the two competitors.",
        "required": [
          "state",
          "competitor_a",
          "competitor_b",
          "competitor_a_is_yes",
          "binding_provenance"
        ],
        "properties": {
          "state": {
            "type": "string",
            "const": "paired"
          },
          "competitor_a": {
            "$ref": "#/components/schemas/GameMarketPriceCompetitor"
          },
          "competitor_b": {
            "$ref": "#/components/schemas/GameMarketPriceCompetitor"
          },
          "competitor_a_is_yes": {
            "type": "boolean",
            "description": "Whether competitor A is the provider YES leg."
          },
          "binding_provenance": {
            "$ref": "#/components/schemas/GameMarketPriceBindingProvenance"
          }
        }
      },
      "GameMarketPriceIncomplete": {
        "type": "object",
        "description": "The provider moneyline pair is incomplete; no numeric pair is invented.",
        "required": ["state", "reason"],
        "properties": {
          "state": {
            "type": "string",
            "const": "incomplete"
          },
          "reason": {
            "type": "string",
            "enum": [
              "outcome_prices_missing",
              "outcome_price_leg_missing",
              "zero_price_sentinel",
              "display_price_pair_unavailable",
              "outcome_identity_unavailable",
              "final_score_unavailable"
            ]
          },
          "competitor_a_is_yes": {
            "type": "boolean",
            "description": "Whether competitor A is the provider YES leg."
          },
          "competitor_a_provider_id": {
            "type": "integer",
            "format": "int64",
            "description": "The provider competitor id when identity is available."
          },
          "competitor_b_provider_id": {
            "type": "integer",
            "format": "int64",
            "description": "The provider competitor id when identity is available."
          },
          "binding_provenance": {
            "$ref": "#/components/schemas/GameMarketPriceBindingProvenance"
          }
        }
      },
      "GameMarketPriceInvalid": {
        "type": "object",
        "description": "The provider moneyline pair is invalid; no numeric pair is invented.",
        "required": ["state", "reason"],
        "properties": {
          "state": {
            "type": "string",
            "const": "invalid"
          },
          "reason": {
            "type": "string",
            "enum": [
              "team_cardinality",
              "outcome_cardinality",
              "price_cardinality",
              "non_finite_price",
              "out_of_range_price",
              "non_complementary_prices",
              "ambiguous_identity",
              "final_identity_mismatch"
            ]
          },
          "competitor_a_is_yes": {
            "type": "boolean",
            "description": "Whether competitor A is the provider YES leg."
          },
          "competitor_a_provider_id": {
            "type": "integer",
            "format": "int64",
            "description": "The provider competitor id when identity is available."
          },
          "competitor_b_provider_id": {
            "type": "integer",
            "format": "int64",
            "description": "The provider competitor id when identity is available."
          },
          "binding_provenance": {
            "$ref": "#/components/schemas/GameMarketPriceBindingProvenance"
          }
        }
      },
      "GameMarketProviderPrices": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/GameMarketPricePaired"
          },
          {
            "$ref": "#/components/schemas/GameMarketPriceIncomplete"
          },
          {
            "$ref": "#/components/schemas/GameMarketPriceInvalid"
          }
        ],
        "discriminator": {
          "propertyName": "state",
          "mapping": {
            "paired": "#/components/schemas/GameMarketPricePaired",
            "incomplete": "#/components/schemas/GameMarketPriceIncomplete",
            "invalid": "#/components/schemas/GameMarketPriceInvalid"
          }
        }
      },
      "GameMarketPrices": {
        "type": "object",
        "description": "Provider-owned moneyline state with the observation clock that can be compared with game freshness.",
        "required": ["provider", "observed_at", "observation_source"],
        "properties": {
          "provider": {
            "$ref": "#/components/schemas/GameMarketProviderPrices"
          },
          "observed_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Board cache vintage for Gamma or the older CLOB leg clock. Null when no reliable clock is available; never a Gamma-authored timestamp."
          },
          "observation_source": {
            "type": "string",
            "enum": ["board_snapshot", "clob_display"],
            "description": "The clock used for observed_at. board_snapshot is this service’s cache observation, not a provider source timestamp."
          }
        }
      },
      "GameMarket": {
        "type": "object",
        "description": "One Polymarket market linked to this game.",
        "required": ["id", "condition_id", "platform"],
        "properties": {
          "id": {
            "type": "string",
            "description": "The mkt_-prefixed market id every other V1 response uses."
          },
          "condition_id": {
            "type": "string",
            "description": "The raw provider condition id."
          },
          "platform": {
            "type": "string",
            "enum": ["polymarket"],
            "description": "Always polymarket."
          },
          "slug": {
            "type": "string",
            "description": "The provider's market slug. Omitted when the provider sent none."
          },
          "sports_market_type": {
            "type": "string",
            "description": "The provider's own market type, for example moneyline or spread. Omitted when the provider sent none. Not an enum: the provider owns this vocabulary and adds to it."
          },
          "side": {
            "type": "string",
            "enum": ["home", "away", "draw", "other"],
            "description": "Which side of the game this market's YES leg pays. home and away are the provider's own home/away designation of the team the YES leg names (Polymarket's teams[].ordering), never its place in competitors. Soccer 1X2 legs are explicitly classified as home, draw or away by the provider projection. draw is a real value, not a competitor. Omitted when the provider projection cannot classify the leg or the provider designates neither team home or away, which is not the same as other."
          },
          "outcome_yes": {
            "type": "string",
            "description": "The provider's label for the YES outcome. Omitted when the provider sent none."
          },
          "outcome_no": {
            "type": "string",
            "description": "The provider's label for the NO outcome. Omitted when the provider sent none."
          },
          "outcome_token_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Polymarket CLOB token ids in the provider's own outcome-index order. Omitted when the provider has published none for this market."
          },
          "prices": {
            "$ref": "#/components/schemas/GameMarketPrices",
            "description": "Default provider moneyline state. Omitted when this market has no classified moneyline projection; incomplete and invalid projections remain explicit."
          },
          "liquidity": {
            "$ref": "#/components/schemas/GameMarketLiquidity",
            "description": "Polymarket's reported liquidity for this market. Omitted when the provider read carried none, and on a finished game read from its stored record; never 0 in place of a missing figure."
          },
          "settlement": {
            "description": "How Polymarket's oracle settled or is settling this market, the block GET /api/v1/games/{event_slug}/markets serves, from the same per-game store. Always present on GET /api/v1/games/{event_slug}; on GET /api/v1/games only with expand=settlement. It never waits for Polymarket: a settled market reads its recorded settlement on the first read, and any other market of a game not read lately reads status unavailable while its read starts.",
            "type": "object",
            "required": [
              "status",
              "oracle_status",
              "settled",
              "payouts",
              "result",
              "winning_outcome_index",
              "was_disputed",
              "resolved_at",
              "expected_settlement_time",
              "settlement_time_basis",
              "proposed_answer",
              "observed_at"
            ],
            "properties": {
              "expected_settlement_time": {
                "type": ["string", "null"],
                "format": "date-time"
              },
              "observed_at": {
                "type": ["string", "null"],
                "format": "date-time"
              },
              "oracle_status": {
                "type": ["string", "null"]
              },
              "payouts": {
                "type": ["array", "null"],
                "items": {
                  "type": "integer"
                }
              },
              "proposed_answer": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": ["outcome_0", "outcome_1", "split", "too_early"]
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "resolved_at": {
                "type": ["string", "null"],
                "format": "date-time"
              },
              "result": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": ["outcome", "split"]
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "settled": {
                "type": ["boolean", "null"]
              },
              "settlement_time_basis": {
                "type": ["string", "null"]
              },
              "status": {
                "type": "string",
                "enum": ["observed", "not_posed", "unavailable"]
              },
              "was_disputed": {
                "type": ["boolean", "null"]
              },
              "winning_outcome_index": {
                "type": ["integer", "null"]
              }
            }
          }
        }
      },
      "GameMarketLiquidity": {
        "type": "object",
        "description": "One market's liquidity as Polymarket reports it (Gamma liquidityNum), verbatim. Polymarket documents it only as reported market liquidity, with no unit. It describes the market's resting order book, not traded volume.",
        "required": ["value", "source"],
        "properties": {
          "value": {
            "type": "number",
            "description": "The provider's figure at full precision."
          },
          "source": {
            "type": "string",
            "enum": ["gamma"],
            "description": "Always gamma: the Polymarket Gamma API."
          },
          "observed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When 0xinsider read the sports board body this figure came from, never a provider-authored timestamp. Omitted when that read has no clock."
          }
        }
      },
      "GameFreshness": {
        "type": "object",
        "description": "How current this game's facts are. Independent per source: the board half that produced the game, and the live-score frame that produced its scores.",
        "required": [
          "source",
          "source_status",
          "source_availability",
          "source_freshness",
          "delayed",
          "scores_freshness"
        ],
        "properties": {
          "source": {
            "type": "string",
            "enum": ["live", "upcoming", "stored"],
            "description": "What produced this game: live or upcoming, the board half that carried it, or stored, the stored record of a finished game that has left the board (GET /api/v1/games/{event_slug}, and GET /api/v1/games with a finished status)."
          },
          "source_status": {
            "type": "string",
            "enum": ["ok", "unavailable"],
            "description": "Whether that half returned a truthful source body for this read."
          },
          "source_availability": {
            "type": "string",
            "enum": ["available", "unavailable", "not_applicable"],
            "description": "Whether that half had a source body at all. not_applicable means the sport has no configured source for that half."
          },
          "source_freshness": {
            "type": "string",
            "enum": ["fresh", "stale", "unknown", "not_applicable"],
            "description": "Freshness of the cached source body, never inferred from the response clock or the row count. not_applicable for a stored game, whose record is final."
          },
          "source_observed_at": {
            "type": "string",
            "format": "date-time",
            "description": "The source body's data vintage. Omitted when the read has no vintage anchor, which is not age zero. For a stored game, the later of its last live-score write and its last leg settlement."
          },
          "source_age_seconds": {
            "type": "integer",
            "description": "Age of source_observed_at in seconds, capped at 600. Omitted past the cap or with no anchor."
          },
          "delayed": {
            "type": "boolean",
            "description": "Whether a reader should be told these rows are behind. This applies the half's own servable-age bar (15 s live, 120 s upcoming), which is not the same as source_freshness: a live board whose scores are seconds old reads stale for about half of every publish cycle and is not delayed."
          },
          "scores_observed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When this game's live-score frame was observed. Omitted when there is no frame."
          },
          "scores_source_at": {
            "type": "string",
            "format": "date-time",
            "description": "The provider's own frame clock. Omitted when the frame carries none."
          },
          "scores_age_seconds": {
            "type": "integer",
            "minimum": 0,
            "description": "Seconds since this game's last Sports WebSocket frame. The esports feed resends an unchanged series about every 20 seconds, so this dates the feed's last frame, not the last score change. Omitted when no Sports WebSocket frame dates the score, which is not age zero: a score read from the provider's event listing is re-read on a cadence whether or not the game moved."
          },
          "scores_freshness": {
            "type": "string",
            "enum": ["fresh", "stale", "unknown", "not_applicable"],
            "description": "Whether this game's score and clock are current, judged on how often this league's feed sends a frame, and independent of source_freshness, which dates the board: a board can be seconds old while one game's frame is frozen. not_applicable outside play (scheduled, final, postponed, cancelled), at halftime and in a break between periods (a period of HT or End ...). stale when the last frame is older than the bound measured for its state: 180 seconds for a running soccer half before stoppage time (the provider sends a frame each match minute); 120 seconds for an in-progress cs2 or lol series (the feed resends each running series about every 20 seconds, so fresh means the provider resent it, not that the map score moved); 600 seconds for a running period of men's and women's college basketball (league cbb, cwbb) and NHL hockey (nhl), whose feeds send no frame while the clock is stopped for a timeout or review. fresh within the bound. unknown otherwise: no dated frame, soccer stoppage time, a period clock at 00:00, End OT in women's college basketball (the end of the third quarter, after which the provider sends no frame until the final), tennis (frames land on points and stop for changeovers and breaks), and every league with no measured bound, including the NBA and NFL."
          }
        }
      },
      "GameCoverage": {
        "type": "object",
        "description": "What this game's read actually supplied, so a client branches on coverage instead of on a missing key.",
        "required": ["scores", "competitors", "schedule"],
        "properties": {
          "scores": {
            "type": "string",
            "enum": ["available", "unavailable"],
            "description": "available when a live-score frame supplied a score for this game. A game no live-score feed has reported yet, as most scheduled games are, reads unavailable."
          },
          "competitors": {
            "type": "string",
            "enum": ["provider_ids", "labels", "unavailable"],
            "description": "provider_ids when every side carries a provider id, labels when only the provider's names identify them, unavailable when neither exists. Do not join on names when this reads labels."
          },
          "schedule": {
            "type": "string",
            "enum": ["available", "unavailable"],
            "description": "available when the provider supplied a kickoff."
          }
        }
      },
      "GamesCoverage": {
        "type": "object",
        "description": "What this deployment covers, published with every page so a client never has to guess whether an empty list means no games or no coverage.",
        "required": ["sports", "leagues", "sources_unavailable"],
        "properties": {
          "sports": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Canonical sport buckets served, sorted."
          },
          "leagues": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "League tags served, sorted. EuroLeague is euroleague, NCAA men's college basketball cbb and NCAA women's college basketball cwbb, all under the Basketball sport bucket."
          },
          "sources_unavailable": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Scopes whose source half was unavailable for this read, as <sport>:<half>. Empty means every scope answered."
          }
        }
      },
      "ResponseMeta": {
        "type": "object",
        "required": ["request_id", "cached", "cost"],
        "properties": {
          "request_id": {
            "type": "string",
            "description": "Unique request ID (req_ prefix). The same value as the X-Request-Id response header, the request's usage accounting row and its log lines."
          },
          "cached": {
            "type": "boolean"
          },
          "cache_age_s": {
            "type": "integer",
            "description": "Cache age in seconds. Omitted when the response was not cached, and also when it was cached but its age cannot be established (an entry stored before its cache carried a computed instant). Never a placeholder: an unknown age is reported as no value rather than as the cache TTL."
          },
          "cost": {
            "type": "integer",
            "description": "Advisory request weight (relative compute cost). 1 for simple reads; higher for heavier endpoints. Not a credit/price."
          },
          "ranking_generation": {
            "type": "integer",
            "description": "Committed PostgreSQL-owned leaderboard generation for the returned rows and cursor. Present on GET /api/v1/leaderboard; omitted on endpoints that do not read this ranking."
          },
          "ranking_as_of": {
            "type": "string",
            "format": "date-time",
            "description": "Authoritative RFC3339 timestamp from cache_generations.updated_at for ranking_generation. It is read in the same repeatable-read snapshot as the leaderboard rows and is not request time, cache write time, or row insertion order."
          },
          "continued_from_generation": {
            "type": "integer",
            "description": "GET /api/v1/leaderboard only. The cursor's ranking_generation, set when this page continued a cursor from an earlier ranking that moved under it: the rows follow the cursor's boundary in the ranking named by ranking_generation, so a trader who crossed the boundary can repeat a row you already hold or be missing from the walk. De-duplicate by id, or restart from the first page for an exact walk. Omitted on a first page and on an exact continuation, including a newer generation in which nothing a page of that order reads moved. It can equal ranking_generation when the ranking moved within one generation: on the default order, sort=rank and sort=grade when the rank keys changed, and on every other sort whenever the projection republished (about once a minute; since 2026-11-07)."
          },
          "directional_source": {
            "type": "string",
            "enum": ["live", "degraded"],
            "description": "Directional evidence provenance for Edge Hunter signals collections. The default board carries this provenance in data.directional_source and omits this optional meta field."
          },
          "ranking_source": {
            "type": "string",
            "enum": ["live", "db_only"],
            "description": "Ranking evidence provenance for Edge Hunter signals collections. The default board carries this clock/provenance in data.ranking_source and omits this optional meta field."
          },
          "category_skill_source": {
            "type": "string",
            "enum": ["live", "partial", "degraded", "unavailable"],
            "description": "Whole filtered snapshot category-evidence status before pagination. Operational live always remains partial source coverage."
          },
          "category_skill_model_version": {
            "type": "string"
          },
          "category_skill_taxonomy_version": {
            "type": "string"
          },
          "category_skill_platform": {
            "type": "string",
            "const": "polymarket"
          },
          "category_skill_scope": {
            "type": "string",
            "const": "observed_goldsky_primary_taker_fill"
          },
          "category_skill_source_coverage": {
            "type": "string",
            "enum": ["partial_whale_threshold_fills", "graded_wallet_fills"]
          },
          "category_skill_observation_started_at": {
            "type": "string",
            "format": "date-time"
          },
          "category_skill_model_operationally_degraded": {
            "type": "boolean",
            "description": "Whole-model operational readiness captured with the category model snapshot. Present on category-enriched responses even when the filtered signal list is empty. When true, category_skill_source is degraded and Edge Hunter signals uses the shorter degraded cache TTL."
          },
          "category_skill_status_counts": {
            "type": "object",
            "required": ["live", "insufficient", "stale", "unknown", "degraded"],
            "properties": {
              "live": {
                "type": "integer",
                "minimum": 0
              },
              "insufficient": {
                "type": "integer",
                "minimum": 0
              },
              "stale": {
                "type": "integer",
                "minimum": 0
              },
              "unknown": {
                "type": "integer",
                "minimum": 0
              },
              "degraded": {
                "type": "integer",
                "minimum": 0
              }
            }
          },
          "category_skill_base_payload_hash": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "SHA-256 of the funded signal membership/order/rank/cursor vector immediately before category-skill enrichment. Edge Hunter signals view only."
          },
          "category_skill_enriched_base_payload_hash": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "Independent SHA-256 recomputation over the same base fields immediately after category-skill enrichment. Equality with category_skill_base_payload_hash proves category-skill enrichment did not change funded inputs. Edge Hunter signals view only."
          }
        }
      },
      "ApiDiscovery": {
        "type": "object",
        "required": [
          "api_base_url",
          "docs_url",
          "openapi_url",
          "health_url",
          "authentication",
          "protected_resource_metadata_url",
          "authenticated_routes"
        ],
        "properties": {
          "api_base_url": {
            "type": "string",
            "format": "uri",
            "description": "Canonical API origin for public V1 requests."
          },
          "docs_url": {
            "type": "string",
            "format": "uri",
            "description": "Full agent-readable API reference."
          },
          "openapi_url": {
            "type": "string",
            "format": "uri",
            "description": "Canonical web-origin OpenAPI JSON document."
          },
          "health_url": {
            "type": "string",
            "format": "uri",
            "description": "Unauthenticated API health endpoint."
          },
          "authentication": {
            "type": "string",
            "const": "Bearer API key required for data endpoints; discovery (/api/v1), health, coverage (/api/v1/coverage, and its deprecated alias /api/v1/platforms), the Pick of the Day commitment ledger (/api/v1/pick-of-the-day/ledger), and the MCP handshake (initialize, ping, tools/list on /api/v1/mcp) are public. A 401 carries WWW-Authenticate with the resource_metadata URL."
          },
          "protected_resource_metadata_url": {
            "type": "string",
            "format": "uri",
            "description": "RFC 9728 protected-resource metadata for the API origin: the document every V1 401 names in its WWW-Authenticate challenge (resource, bearer_methods_supported, resource_documentation). The remote MCP server has its own document at /.well-known/oauth-protected-resource/api/v1/mcp."
          },
          "authenticated_routes": {
            "type": "array",
            "description": "The complete authenticated route index: one entry per authenticated route this spec documents, in \"<METHOD> <path>\" form, not a representative subset. GET /api/v1 is the unauthenticated entrypoint an agent hits first, so it hands back the whole authenticated surface rather than a sample the caller would have to guess around. The example on GET /api/v1 is abridged for readability -- the live response returns all of them. Kept in lockstep with this spec by review: it is a hand-maintained const in backend/src/api_v1/discovery.rs and no automated check compares the two, so treat this spec as authoritative if they ever disagree.",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "LargeTradeInsertedV2Data": {
        "type": "object",
        "description": "`large_trade_inserted_v2` data (Pro and Max): one large trade, with the trade itself. The three amounts are decimal strings that keep the stored precision: parse them with a decimal library when the exact value matters. The endpoint's `trade_filters` decide which trades it receives.",
        "required": [
          "event_id",
          "whale_alert_id",
          "condition_id",
          "trader_id",
          "wallet",
          "grade",
          "size_usd",
          "shares",
          "price",
          "side",
          "outcome_index",
          "traded_at",
          "platform"
        ],
        "properties": {
          "event_id": {
            "type": "string",
            "description": "Stable identity of this trade's event. It equals the envelope `id`, and the `id` of the same event on `GET /api/v1/events/feed/since`."
          },
          "whale_alert_id": {
            "type": "integer",
            "description": "Numeric id of the trade. `GET /api/v1/large-trades/{id}` accepts it."
          },
          "condition_id": {
            "type": "string",
            "description": "Polymarket condition id of the market."
          },
          "trader_id": {
            "type": "integer",
            "description": "0xinsider's numeric id for the wallet."
          },
          "wallet": {
            "type": "string",
            "description": "Address of the wallet that made the trade."
          },
          "grade": {
            "type": ["string", "null"],
            "enum": ["S", "A", "B", "C", "D", "F", null],
            "description": "The wallet's grade when the event was published; `null` when it has none. A backfilled trade publishes hours after it filled, so this can differ from `grade_at_trade`. `min_grade` filters on this field; `min_grade_at_trade` filters on `grade_at_trade`."
          },
          "size_usd": {
            "type": "string",
            "description": "USD notional of the trade; decimal string."
          },
          "shares": {
            "type": "string",
            "description": "Shares traded; decimal string."
          },
          "price": {
            "type": "string",
            "description": "Price paid per share; decimal string."
          },
          "side": {
            "type": "string",
            "enum": ["BUY", "SELL"]
          },
          "outcome_index": {
            "type": "integer",
            "description": "Polymarket's index of the outcome traded."
          },
          "traded_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the trade filled on Polymarket. The envelope's `created_at` is this instant."
          },
          "platform": {
            "type": "string",
            "const": "polymarket"
          },
          "grade_at_trade": {
            "anyOf": [
              {
                "type": "string",
                "enum": ["S", "A", "B", "C", "D", "F"]
              },
              {
                "type": "null"
              }
            ],
            "description": "The grade the wallet held when the trade filled, the same fact as `trader.grade_at_trade` on `GET /api/v1/large-trades`; `null` unless `grade_at_trade_status` is `graded`. `min_grade_at_trade` filters on it."
          },
          "grade_at_trade_status": {
            "type": "string",
            "enum": ["graded", "ungraded", "unknown"],
            "description": "`graded` when `grade_at_trade` holds the grade at the fill; `ungraded` when the wallet had no grade then; `unknown` when it cannot be known, for a trade before 2026-09-19 23:00 UTC or while a grade change is unconfirmed. Only `graded` trades match `min_grade_at_trade`. An event published before these fields shipped (November 2026), or a redelivery of one, carries neither."
          }
        }
      },
      "LargeTradesInsertedData": {
        "type": "object",
        "description": "`large_trades_inserted` data (Pro and Max): new large trades were ingested. It carries a count and no trade; subscribe to `large_trade_inserted_v2` for the trade itself. The deprecated spelling `whale_trades_inserted` delivers the same object until its sunset on 2027-02-01 (#29352).",
        "required": ["count"],
        "properties": {
          "count": {
            "type": "integer",
            "description": "Large trades the producing batch admitted."
          }
        }
      },
      "LiveSportsScoreEntry": {
        "type": "object",
        "description": "One side's score line inside a `live_sports_updated` pulse.",
        "required": ["team", "score"],
        "properties": {
          "team": {
            "type": "string",
            "description": "Team name, ordered for the league (away first where the league reads that way)."
          },
          "score": {
            "type": "string",
            "description": "This side's score as the provider sends it."
          },
          "map_score": {
            "type": "string",
            "description": "Esports series only: this side's current-map score. Absent on other sports."
          }
        }
      },
      "LiveSportsUpdatedData": {
        "type": "object",
        "description": "`live_sports_updated` data: one bounded pulse for one live game. A pulse fires when a material field moved since this game's previous delivered pulse (`scores`, `status`, `period`, `live`, `ended`), at most once per game per 20 seconds. A `live` or `ended` transition is exempt from that interval, and the game clock alone never fires a pulse. Suppressed frames are folded into the next pulse's `changed`, and its body carries the current state.",
        "required": [
          "event_slug",
          "game_id",
          "league",
          "version",
          "changed",
          "observed_at",
          "published_at",
          "status",
          "period",
          "clock",
          "live",
          "ended",
          "scores",
          "series_format",
          "snapshot_url"
        ],
        "properties": {
          "event_slug": {
            "type": "string",
            "description": "The Polymarket event slug this game trades under."
          },
          "game_id": {
            "type": ["string", "null"],
            "description": "Provider game id, or `null` when the frame carried none."
          },
          "league": {
            "type": ["string", "null"],
            "description": "League abbreviation, or `null`."
          },
          "version": {
            "type": "integer",
            "description": "Durable per-game pulse ordinal, increasing by one per delivered pulse. Deliveries are not ordered, so drop a pulse whose version you already saw."
          },
          "changed": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": ["scores", "status", "period", "live", "ended"]
            },
            "description": "Material fields that moved since this game's previous delivered pulse."
          },
          "observed_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Provider frame time, or `null` when the frame carried none. Never replaced with a local clock."
          },
          "published_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the pulse was admitted."
          },
          "status": {
            "type": ["string", "null"],
            "description": "Provider status text, or `null`."
          },
          "period": {
            "type": ["string", "null"],
            "description": "Provider period text (\"Q3\", \"Map 2/3\"), or `null`."
          },
          "clock": {
            "type": ["string", "null"],
            "description": "Game clock, or `null`. Not a material field: it never fires a pulse on its own."
          },
          "live": {
            "type": ["boolean", "null"],
            "description": "Provider live flag, or `null` when the frame carried none."
          },
          "ended": {
            "type": "boolean",
            "description": "Whether the provider has marked this game final."
          },
          "scores": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LiveSportsScoreEntry"
            },
            "description": "Per-side scores, one line per team."
          },
          "series_format": {
            "type": ["string", "null"],
            "description": "Esports `BoN` series token, or `null` on every other sport."
          },
          "snapshot_url": {
            "type": "string",
            "description": "Public game page. Re-read it after a gap instead of replaying pulses."
          }
        }
      },
      "TraderSyncedData": {
        "type": "object",
        "description": "`trader_synced` data: a tracked wallet finished a sync pass and has a fresh grade. The deprecated spelling `whale_trader_synced` delivers the same object until its sunset on 2027-02-01 (#29352).",
        "required": ["trader_id", "wallet"],
        "properties": {
          "trader_id": {
            "type": "integer",
            "description": "0xinsider's numeric id for the wallet."
          },
          "wallet": {
            "type": "string",
            "description": "Proxy wallet address."
          }
        }
      },
      "LargePositionsUpdatedData": {
        "type": "object",
        "description": "`large_positions_updated` data: one large-positions refresh finished.",
        "required": ["count"],
        "properties": {
          "count": {
            "type": "integer",
            "description": "Positions the refresh published."
          }
        }
      },
      "WalletGradeChangedData": {
        "type": "object",
        "description": "`wallet_grade_changed` data (Pro and Max): a tracked wallet's grade moved on a re-grade.",
        "required": [
          "wallet",
          "trader_id",
          "old_grade",
          "new_grade",
          "direction",
          "skill_index",
          "final_score",
          "date"
        ],
        "properties": {
          "wallet": {
            "type": "string",
            "description": "Lowercased proxy wallet address."
          },
          "trader_id": {
            "type": "integer",
            "description": "0xinsider's numeric id for the wallet."
          },
          "old_grade": {
            "type": "string",
            "enum": ["S", "A", "B", "C", "D", "F"],
            "description": "The grade before the move. Never equal to `new_grade`."
          },
          "new_grade": {
            "type": "string",
            "enum": ["S", "A", "B", "C", "D", "F"]
          },
          "direction": {
            "type": "string",
            "enum": ["upgrade", "downgrade"],
            "description": "`upgrade` when `new_grade` is better than `old_grade`, else `downgrade`."
          },
          "skill_index": {
            "type": "number",
            "description": "Cohort skill index that drove the grade, 0 to 1."
          },
          "final_score": {
            "type": "number",
            "description": "The new grade's sort key, not a rating out of 100: the cohort percentile times 100, held inside the new grade's band."
          },
          "date": {
            "type": "string",
            "format": "date",
            "description": "The ranking date of the re-grade."
          }
        }
      },
      "SuspiciousTradeFlaggedData": {
        "type": "object",
        "description": "`suspicious_trade_flagged` data (Pro and Max): a trade's suspicion score crossed the flag threshold for the first time. The deprecated spelling `insider_radar_flag_raised` delivers the same object until its sunset on 2027-02-01 (#29352).",
        "required": [
          "trade_id",
          "wallet",
          "trader_id",
          "condition_id",
          "suspicion_score",
          "track",
          "side",
          "size",
          "price"
        ],
        "properties": {
          "trade_id": {
            "type": "integer",
            "description": "Numeric id of the flagged trade, a JSON number. It is the `id` that `GET /api/v1/large-trades/{id}` accepts."
          },
          "wallet": {
            "type": "string",
            "description": "Address of the wallet that made the trade."
          },
          "trader_id": {
            "type": "integer",
            "description": "0xinsider's numeric id for the wallet."
          },
          "condition_id": {
            "type": "string",
            "description": "Polymarket condition id of the market."
          },
          "suspicion_score": {
            "type": "number",
            "description": "The suspicion score, 0 to 100, that crossed the threshold."
          },
          "track": {
            "type": "string",
            "enum": ["whale", "fresh_conviction", "sliced_position"],
            "description": "The scoring track that raised the flag."
          },
          "side": {
            "type": "string",
            "enum": ["yes", "no"],
            "description": "Outcome side the flagged fill took."
          },
          "size": {
            "type": "number",
            "description": "Share count of the flagged fill."
          },
          "price": {
            "type": "number",
            "description": "Fill price of the flagged trade."
          }
        }
      },
      "SharpMoneyFlowDetectedData": {
        "type": "object",
        "description": "`sharp_money_flow_detected` data (Pro and Max): ranked-trader net flow on a market crossed the threshold. The deprecated spelling `smart_money_flow_detected` delivers the same object until its sunset on 2027-02-01 (#29352).",
        "required": [
          "condition_id",
          "net_flow_usd",
          "abs_net_flow_usd",
          "dominant_side",
          "grade_floor",
          "whale_trade_count",
          "window"
        ],
        "properties": {
          "condition_id": {
            "type": "string",
            "description": "Polymarket condition id of the market."
          },
          "net_flow_usd": {
            "type": "number",
            "description": "Signed ranked-trader net flow in USD over `window`: positive is net into YES, negative net into NO."
          },
          "abs_net_flow_usd": {
            "type": "number",
            "description": "Absolute value of `net_flow_usd`, the magnitude compared with the threshold."
          },
          "dominant_side": {
            "type": "string",
            "enum": ["yes", "no"],
            "description": "`yes` when `net_flow_usd` is 0 or more, else `no`."
          },
          "grade_floor": {
            "type": "string",
            "enum": ["S", "A", "B", "C", "D", "F"],
            "description": "Minimum trader grade included in the flow."
          },
          "whale_trade_count": {
            "type": "integer",
            "description": "Ranked-trader large fills that make up the flow."
          },
          "window": {
            "type": "string",
            "description": "Window the flow was aggregated over, for example `24h`."
          }
        }
      },
      "ExportJobReadyData": {
        "type": "object",
        "description": "`export_job_ready` data: the owner's asynchronous export can be downloaded. Download authorization stays on the status and download routes.",
        "required": [
          "job_id",
          "status",
          "format",
          "next_action",
          "total_trades",
          "processed_trades",
          "file_size",
          "data_as_of"
        ],
        "properties": {
          "job_id": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "const": "ready",
            "x-narrowed": true
          },
          "format": {
            "type": "string"
          },
          "next_action": {
            "type": "string",
            "const": "download",
            "x-narrowed": true
          },
          "total_trades": {
            "type": ["integer", "null"]
          },
          "processed_trades": {
            "type": ["integer", "null"]
          },
          "file_size": {
            "type": ["integer", "null"],
            "description": "Artifact size in bytes."
          },
          "data_as_of": {
            "type": ["string", "null"],
            "format": "date-time"
          }
        }
      },
      "ExportJobFailedData": {
        "type": "object",
        "description": "`export_job_failed` data: the owner's asynchronous export reached a terminal failure.",
        "required": ["job_id", "status", "format", "next_action", "failure_reason"],
        "properties": {
          "job_id": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "const": "failed",
            "x-narrowed": true
          },
          "format": {
            "type": "string"
          },
          "next_action": {
            "type": "string",
            "const": "resubmit",
            "x-narrowed": true
          },
          "failure_reason": {
            "type": "string"
          }
        }
      },
      "ExportJobExpiredData": {
        "type": "object",
        "description": "`export_job_expired` data: the owner's ready export passed retention.",
        "required": ["job_id", "status", "format", "next_action"],
        "properties": {
          "job_id": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "const": "expired",
            "x-narrowed": true
          },
          "format": {
            "type": "string"
          },
          "next_action": {
            "type": "string",
            "const": "resubmit",
            "x-narrowed": true
          }
        }
      },
      "ExportJobCancelledData": {
        "type": "object",
        "description": "`export_job_cancelled` data: the owner's export stopped because its owner cancelled it.",
        "required": ["job_id", "status", "format", "next_action"],
        "properties": {
          "job_id": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "const": "cancelled",
            "x-narrowed": true
          },
          "format": {
            "type": "string"
          },
          "next_action": {
            "type": "string",
            "const": "resubmit",
            "x-narrowed": true
          }
        }
      },
      "MarketPriceMovedData": {
        "type": "object",
        "description": "`market_price_moved` data, also the MarketPriceMoved frame on GET /api/v1/stream: a sports or esports market's outcome-0 midpoint moved a whole-cent level over one window. Prices are decimal strings at full precision. A missing value is null with its *_unavailable_reason.",
        "properties": {
          "best_ask": {
            "type": "string"
          },
          "best_bid": {
            "type": "string"
          },
          "concurrent_sharp_flow": {
            "anyOf": [
              {
                "type": "object",
                "required": [
                  "detected",
                  "net_flow_usd",
                  "ranked_large_trades",
                  "grade_floor",
                  "large_trades_in_window"
                ],
                "properties": {
                  "detected": {
                    "type": "boolean"
                  },
                  "grade_floor": {
                    "type": "string",
                    "enum": ["S", "A", "B", "C", "D", "F"]
                  },
                  "net_flow_usd": {
                    "type": "number"
                  },
                  "ranked_large_trades": {
                    "type": "integer"
                  },
                  "large_trades_in_window": {
                    "type": ["integer", "null"],
                    "description": "Large trades on the market in the same window at any grade, ungraded wallets included. ranked_large_trades is the part of them at grade_floor or better."
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "concurrent_sharp_flow_unavailable_reason": {
            "anyOf": [
              {
                "type": "string",
                "enum": ["read_failed"]
              },
              {
                "type": "null"
              }
            ]
          },
          "condition_id": {
            "type": "string"
          },
          "detected_at": {
            "type": "string",
            "format": "date-time"
          },
          "direction": {
            "type": "string",
            "enum": ["up", "down"]
          },
          "event_slug": {
            "type": ["string", "null"]
          },
          "from_price": {
            "type": "string"
          },
          "game_state": {
            "anyOf": [
              {
                "type": "object",
                "required": ["status", "period", "clock", "live", "ended", "scores", "updated_at"],
                "properties": {
                  "clock": {
                    "type": ["string", "null"]
                  },
                  "ended": {
                    "type": "boolean"
                  },
                  "live": {
                    "type": ["boolean", "null"]
                  },
                  "period": {
                    "type": ["string", "null"]
                  },
                  "scores": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/LiveSportsScoreEntry"
                    }
                  },
                  "status": {
                    "type": ["string", "null"]
                  },
                  "updated_at": {
                    "type": "string",
                    "format": "date-time"
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "game_state_unavailable_reason": {
            "anyOf": [
              {
                "type": "string",
                "enum": ["no_event_slug", "no_game_state", "read_failed"]
              },
              {
                "type": "null"
              }
            ]
          },
          "gap_before": {
            "type": "boolean"
          },
          "label": {
            "type": ["string", "null"]
          },
          "league": {
            "type": ["string", "null"]
          },
          "level_cents": {
            "type": "integer"
          },
          "market_slug": {
            "type": ["string", "null"]
          },
          "move_cents": {
            "type": "string"
          },
          "observed_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "outcome_index": {
            "type": "integer"
          },
          "phase": {
            "type": "string",
            "enum": ["pre_game", "in_play", "unknown"],
            "description": "Where the game stood at detected_at. in_play: its live state reports it live. pre_game: its live state is neither live nor ended, or it has no live state yet and the market's scheduled start (the games endpoints' scheduled_at) is after detected_at. unknown: neither holds or the live state could not be read; game_state_unavailable_reason says why."
          },
          "previous_level_cents": {
            "type": "integer"
          },
          "source": {
            "type": "string"
          },
          "spread_cents": {
            "type": "string"
          },
          "to_price": {
            "type": "string"
          },
          "window_seconds": {
            "type": "integer"
          },
          "window_start": {
            "type": "string",
            "format": "date-time"
          },
          "book_depth_unavailable_reason": {
            "anyOf": [
              {
                "type": "string",
                "enum": ["no_book", "book_changed", "band_not_covered"]
              },
              {
                "type": "null"
              }
            ],
            "description": "Why book_depth_within_2c is null, and null when it is present. no_book: no full order book has arrived for the market since tracking began, only quotes. book_changed: the best bid or ask moved after the latest full book, so its depth belongs to another top. band_not_covered: the latest full book shows no level beyond 2 cents from the midpoint on at least one side, so that side's sum could be cut short."
          },
          "book_depth_within_2c": {
            "anyOf": [
              {
                "type": "object",
                "required": ["bid_usd", "ask_usd", "book_observed_at"],
                "properties": {
                  "ask_usd": {
                    "type": "string",
                    "description": "USD resting on asks priced at or below the midpoint plus 0.02 (price times size), as a decimal string."
                  },
                  "bid_usd": {
                    "type": "string",
                    "description": "USD resting on bids priced at or above the midpoint minus 0.02 (price times size), as a decimal string."
                  },
                  "book_observed_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When we received the full order book the sums come from. Its best bid and ask are the event's best_bid and best_ask; deeper levels may have changed since."
                  }
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "USD resting within 2 cents of outcome 0's midpoint on each side at detected_at, or null with book_depth_unavailable_reason."
          }
        },
        "required": [
          "condition_id",
          "event_slug",
          "market_slug",
          "league",
          "outcome_index",
          "label",
          "direction",
          "from_price",
          "to_price",
          "move_cents",
          "level_cents",
          "previous_level_cents",
          "window_seconds",
          "window_start",
          "observed_at",
          "detected_at",
          "best_bid",
          "best_ask",
          "spread_cents",
          "phase",
          "game_state",
          "game_state_unavailable_reason",
          "concurrent_sharp_flow",
          "concurrent_sharp_flow_unavailable_reason",
          "gap_before",
          "source",
          "book_depth_within_2c",
          "book_depth_unavailable_reason"
        ]
      },
      "LargeTradeHistoryMeta": {
        "type": "object",
        "required": ["request_id", "cached", "source", "completeness"],
        "properties": {
          "request_id": {
            "type": "string",
            "description": "Unique request ID (req_ prefix). The same value as the X-Request-Id response header, the request's usage accounting row and its log lines."
          },
          "cached": {
            "type": "boolean"
          },
          "cache_age_s": {
            "type": "integer",
            "description": "Cache age in seconds; the key is absent when the response was not cached."
          },
          "source": {
            "type": "object",
            "required": ["kind", "table", "provider_fetch_at_request_time"],
            "properties": {
              "kind": {
                "type": "string",
                "const": "local_replay"
              },
              "table": {
                "type": "string",
                "const": "whale_alerts"
              },
              "provider_fetch_at_request_time": {
                "type": "boolean",
                "const": false
              }
            }
          },
          "completeness": {
            "type": "object",
            "required": ["status", "reason"],
            "properties": {
              "status": {
                "type": "string",
                "const": "best_effort"
              },
              "reason": {
                "type": "string",
                "description": "Explains that local replay completeness can vary by market and time window."
              }
            }
          }
        }
      },
      "EventReplayEvent": {
        "type": "object",
        "required": [
          "id",
          "type",
          "cursor",
          "sequence",
          "published_at",
          "payload",
          "source",
          "freshness"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Opaque event identity: the ef_-encoded whale_alerts.id, stable across cursor formats. Deduplicate on this, never on cursor or sequence."
          },
          "type": {
            "type": "string",
            "enum": ["whale_trades_inserted"]
          },
          "cursor": {
            "type": "string",
            "description": "Cursor positioned at this event: its (inserted_xid, id) commit-order position. Store the page's next_cursor to continue; this one resumes from exactly this event."
          },
          "sequence": {
            "type": "integer",
            "minimum": 1,
            "description": "whale_alerts.id of the event. Not monotonic across a replay: events arrive in commit order, so a lower id can follow a higher one when its write finished later. Order and resume by cursor, deduplicate by id."
          },
          "published_at": {
            "type": "string",
            "format": "date-time"
          },
          "payload": {
            "type": "object",
            "description": "What the event announces. Every field is present on every event; a field added later is additive, so a client tolerates keys it does not know.",
            "required": ["count", "whale_alert_id", "condition_id", "trader_id", "platform"],
            "properties": {
              "count": {
                "type": "integer",
                "minimum": 1,
                "description": "Whale trades this event announces. One event is minted per stored whale trade, so this is 1."
              },
              "whale_alert_id": {
                "type": "integer",
                "minimum": 1,
                "description": "The raw whale_alerts.id of the trade, the same number as sequence. GET /api/v1/whale-trades/{id} accepts it and returns the trade with its wallet, grade, size, price and market."
              },
              "condition_id": {
                "type": "string",
                "description": "The Polymarket condition id of the market the trade was in."
              },
              "trader_id": {
                "type": "integer",
                "description": "0xinsider's numeric id for the wallet's trader row. It is not the trd_ id, which is derived from the address; read the address and grade from the whale trade."
              },
              "platform": {
                "type": "string",
                "enum": ["polymarket"],
                "description": "Provider discriminator. Polymarket only."
              }
            },
            "additionalProperties": true
          },
          "trade": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/LargeTrade"
              },
              {
                "type": "null"
              }
            ],
            "description": "Present only with expand=trade: the base trade fields for this row, read at request time from one query per page. GET /api/v1/large-trades/{id} adds counterparty_analysis; replay does not include it. traded_at, side, size_usd, price, outcome, token_id, recorded_signal_score and trader.grade_at_trade with its status are the row's event-time facts; trader.grade, trader.username, signal_score, suspicion_score, suspicion_track and market title/slug/category are enrichment that can move after the event. null when that route would answer 404 for the row (its trader or market is not synced yet)."
          },
          "source": {
            "$ref": "#/components/schemas/EventReplaySource"
          },
          "freshness": {
            "$ref": "#/components/schemas/EventReplayFreshness"
          }
        }
      },
      "EventReplaySource": {
        "type": "object",
        "required": ["kind", "producer_family", "owner", "provider_fetch_at_request_time"],
        "properties": {
          "kind": {
            "type": "string",
            "const": "local_durable_replay"
          },
          "producer_family": {
            "type": "string",
            "enum": ["whale_trades"]
          },
          "owner": {
            "type": "string",
            "const": "whale_alerts"
          },
          "provider_fetch_at_request_time": {
            "type": "boolean",
            "const": false
          }
        }
      },
      "EventReplayFreshness": {
        "type": "object",
        "required": ["status", "observed_at"],
        "properties": {
          "status": {
            "type": "string",
            "const": "observed"
          },
          "observed_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "EventReplayMeta": {
        "type": "object",
        "required": ["request_id", "cached", "cost", "replay", "retention", "completeness"],
        "properties": {
          "request_id": {
            "type": "string",
            "description": "Unique request ID (req_ prefix). The same value as the X-Request-Id response header, the request's usage accounting row and its log lines."
          },
          "cached": {
            "type": "boolean"
          },
          "cost": {
            "type": "integer",
            "description": "Advisory request weight (relative compute cost). 1 for simple reads; higher for heavier endpoints. Not a credit/price."
          },
          "replay": {
            "type": "object",
            "required": [
              "from_cursor",
              "to_cursor",
              "from_sequence",
              "to_sequence",
              "ordering",
              "pending_beyond_horizon",
              "expand"
            ],
            "properties": {
              "from_cursor": {
                "type": "string",
                "description": "The request cursor in canonical form (an id-only cursor is re-encoded), or the zero position when omitted."
              },
              "to_cursor": {
                "type": "string",
                "description": "Identical to next_cursor. After a full page, the cursor of the last event; after a page that is not full, the commit horizon itself, since every row below it, matching or not, has been examined. An empty page therefore still advances."
              },
              "from_sequence": {
                "type": "integer",
                "minimum": 0,
                "description": "whale_alerts.id component of the request cursor (0 when omitted)."
              },
              "to_sequence": {
                "type": "integer",
                "minimum": 0,
                "description": "whale_alerts.id of the last event on this page, or from_sequence when the page is empty. Can sit below the position next_cursor encodes after a page that is not full."
              },
              "ordering": {
                "type": "string",
                "const": "commit_visibility_then_id_asc",
                "description": "Events are ordered by the position at which their write became visible (whale_alerts.inserted_xid), then by whale_alerts.id, and a page is bounded by the oldest write transaction still open when it was read. Before 2026-09-22 this read whale_alerts_id_asc; that order could skip a late-committing lower id (#16180)."
              },
              "pending_beyond_horizon": {
                "type": "boolean",
                "description": "True when committed whale-trade rows newer than this page's commit-visibility horizon exist. They are held until every older write transaction has finished and are served on a later request, so a caught_up page with this true is not the end of the stream: poll again. A long open write transaction on the database (a single-transaction backfill) is what keeps this true for more than a few seconds."
              },
              "filters": {
                "type": "object",
                "description": "The effective filter set this page ran with and next_cursor is bound to. Absent on an unfiltered walk.",
                "properties": {
                  "trader": {
                    "type": "string",
                    "description": "The trader parameter as given."
                  },
                  "condition_id": {
                    "type": "string",
                    "description": "The raw provider condition id after mkt_ is stripped."
                  },
                  "min_grade": {
                    "type": "string",
                    "enum": ["S", "A", "B", "C", "D", "F"]
                  },
                  "min_size": {
                    "type": "number"
                  },
                  "min_grade_at_trade": {
                    "type": "string",
                    "enum": ["S", "A", "B", "C", "D", "F"]
                  }
                }
              },
              "expand": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": ["trade"]
                },
                "description": "The expansions applied to every event on this page; empty when none."
              }
            }
          },
          "retention": {
            "type": "object",
            "required": ["status", "retained_events", "cursor_expired"],
            "properties": {
              "status": {
                "type": "string",
                "enum": ["durable_database"]
              },
              "retained_events": {
                "type": "integer",
                "minimum": 0
              },
              "cursor_expired": {
                "type": "boolean",
                "const": false
              }
            }
          },
          "completeness": {
            "type": "object",
            "required": ["status", "reason"],
            "properties": {
              "status": {
                "type": "string",
                "enum": ["complete", "caught_up"],
                "description": "complete: the page carries every durable event matching the filters after the cursor below the commit horizon, up to limit. caught_up: nothing matching after the cursor is visible below the horizon; read pending_beyond_horizon to tell an idle stream from held rows, and note next_cursor has still advanced to the horizon."
              },
              "reason": {
                "type": "string"
              }
            }
          }
        }
      },
      "TrustSource": {
        "type": "object",
        "description": "Source metadata for a trust-critical value. Providers and DB/read models own business truth; clients should not infer missing provider facts from titles, slugs, zeros, or empty arrays.",
        "required": ["kind", "owner"],
        "properties": {
          "kind": {
            "type": "string",
            "enum": ["provider", "database", "cache", "computed", "client_input", "unavailable"]
          },
          "owner": {
            "type": "string",
            "description": "Provider, table/read-model, cache, or service that owns the value."
          },
          "field": {
            "type": "string",
            "description": "Provider field, DB column, or computed field name when applicable."
          }
        }
      },
      "TrustFreshness": {
        "type": "object",
        "description": "Freshness metadata for a trust-critical value. This is separate from transport cache fields in ResponseMeta.",
        "required": ["status"],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["fresh", "refreshing", "stale", "not_live", "unknown", "unavailable"]
          },
          "as_of": {
            "type": "string",
            "format": "date-time"
          },
          "max_age_s": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "TrustReconciliation": {
        "type": "object",
        "description": "How provider-owned facts were reconciled with stored/read-model values.",
        "required": ["status"],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "provider_backed",
              "db_mirror",
              "computed",
              "partial",
              "not_applicable",
              "unavailable"
            ]
          },
          "detail": {
            "type": "string"
          }
        }
      },
      "TrustCompleteness": {
        "type": "object",
        "description": "Whether the described value or result set is complete for its stated contract.",
        "required": ["status"],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["complete", "partial", "not_computed", "not_applicable", "unavailable"]
          },
          "detail": {
            "type": "string"
          }
        }
      },
      "TrustMetadata": {
        "type": "object",
        "description": "Shared source/freshness/reconciliation/completeness metadata for public API values that may be cached, stale, partial, computed, or provider-unavailable. Unavailable provider values must be represented with explicit metadata instead of fabricated zeros or empty arrays.",
        "required": ["source", "freshness", "reconciliation", "completeness"],
        "properties": {
          "source": {
            "$ref": "#/components/schemas/TrustSource"
          },
          "freshness": {
            "$ref": "#/components/schemas/TrustFreshness"
          },
          "reconciliation": {
            "$ref": "#/components/schemas/TrustReconciliation"
          },
          "completeness": {
            "$ref": "#/components/schemas/TrustCompleteness"
          }
        }
      },
      "DataQualityGroup": {
        "type": "object",
        "description": "One group of response fields that share a writer and therefore share a clock.",
        "required": ["group", "owner", "status"],
        "properties": {
          "group": {
            "type": "string",
            "description": "Stable snake_case group name. Names are additive across releases, so match on the ones you know and ignore the rest."
          },
          "owner": {
            "type": "string",
            "description": "The table and column that write this group, named so the verdict can be audited (for example trader_rankings.computed_at)."
          },
          "status": {
            "type": "string",
            "enum": ["fresh", "stale", "partial", "unknown", "untracked", "unavailable"],
            "description": "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."
          },
          "as_of": {
            "type": "string",
            "format": "date-time",
            "description": "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."
          },
          "reason": {
            "type": "string",
            "description": "Why the status is not fresh. Omitted when it is."
          },
          "max_age_s": {
            "type": "integer",
            "minimum": 0,
            "description": "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."
          }
        }
      },
      "DataQuality": {
        "type": "object",
        "description": "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.",
        "required": ["status", "field_groups"],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["fresh", "stale", "partial", "unknown", "untracked", "unavailable"],
            "description": "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."
          },
          "as_of": {
            "type": "string",
            "format": "date-time",
            "description": "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."
          },
          "field_groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataQualityGroup"
            },
            "description": "One entry per field group. Entries may be added in later releases, so match on group rather than on position or length."
          }
        }
      },
      "TraderTrust": {
        "type": "object",
        "description": "Field-level trust metadata returned only when GET /api/v1/trader/{address} includes expand=trust.",
        "required": [
          "total_pnl",
          "realized_pnl",
          "net_total_pnl",
          "unrealized_pnl",
          "markets_traded",
          "win_rate",
          "daily_win_rate",
          "total_volume",
          "grade",
          "score",
          "forecast_score",
          "forecast_evidence",
          "rank",
          "streak_tier",
          "strategy",
          "category_strengths",
          "quant_metrics",
          "last_active",
          "synced_at",
          "sync_status",
          "category_records",
          "category_skill_model"
        ],
        "properties": {
          "total_pnl": {
            "$ref": "#/components/schemas/TrustMetadata",
            "description": "Since 2026-10-27 always not_computed: pnl.total is retired and never sent (#29830). The key stays so the object keeps its shape."
          },
          "realized_pnl": {
            "$ref": "#/components/schemas/TrustMetadata",
            "description": "Since 2026-10-27 always not_computed: pnl.realized and pnl.exact are retired and never sent (#29830). The key stays so the object keeps its shape."
          },
          "net_total_pnl": {
            "$ref": "#/components/schemas/TrustMetadata",
            "description": "Since 2026-10-27 always not_computed: pnl.net_total is retired and never sent (#29830). The key stays so the object keeps its shape."
          },
          "pnl_correction": {
            "$ref": "#/components/schemas/TrustMetadata",
            "deprecated": true,
            "x-never-sent": true,
            "description": "Deprecated since 2026-10-27 and never sent: it was present only with pnl.correction, which is retired (#29830)."
          },
          "unrealized_pnl": {
            "$ref": "#/components/schemas/TrustMetadata"
          },
          "markets_traded": {
            "$ref": "#/components/schemas/TrustMetadata",
            "description": "Computed, owned by trader_product_scope_records (markets) and dated by the record's computed_at, since 2026-10-27 (#29830). For a wallet that traded no sports or esports market, which never gets a record, owned by traders (last_synced), the completed sync that found none, and dated by it, since 2026-10-29 (#30589, #30657; owned by traders (markets_traded) until #30657)."
          },
          "win_rate": {
            "$ref": "#/components/schemas/TrustMetadata",
            "description": "Computed, owned by trader_product_scope_records (win_rate) and dated by the record's computed_at, since 2026-10-27 (#29830)."
          },
          "daily_win_rate": {
            "$ref": "#/components/schemas/TrustMetadata",
            "description": "Since 2026-10-27 always not_computed: stats.daily_win_rate is retired and never sent (#29830). The key stays so the object keeps its shape."
          },
          "total_volume": {
            "$ref": "#/components/schemas/TrustMetadata",
            "description": "Computed, owned by trader_trade_daily_rollups (in_scope_volume_total) and dated by traders.last_synced, since 2026-10-27 (#29830)."
          },
          "grade": {
            "$ref": "#/components/schemas/TrustMetadata"
          },
          "score": {
            "$ref": "#/components/schemas/TrustMetadata"
          },
          "forecast_score": {
            "$ref": "#/components/schemas/TrustMetadata"
          },
          "forecast_evidence": {
            "$ref": "#/components/schemas/TrustMetadata"
          },
          "rank": {
            "$ref": "#/components/schemas/TrustMetadata"
          },
          "streak_tier": {
            "$ref": "#/components/schemas/TrustMetadata"
          },
          "strategy": {
            "$ref": "#/components/schemas/TrustMetadata"
          },
          "category_strengths": {
            "$ref": "#/components/schemas/TrustMetadata"
          },
          "quant_metrics": {
            "$ref": "#/components/schemas/TrustMetadata"
          },
          "last_active": {
            "$ref": "#/components/schemas/TrustMetadata"
          },
          "synced_at": {
            "$ref": "#/components/schemas/TrustMetadata"
          },
          "sync_status": {
            "$ref": "#/components/schemas/TrustMetadata"
          },
          "category_records": {
            "$ref": "#/components/schemas/TrustMetadata"
          },
          "category_skill_model": {
            "$ref": "#/components/schemas/TrustMetadata"
          }
        }
      },
      "PlatformCapabilityStatus": {
        "type": "string",
        "enum": ["supported"],
        "description": "Every capability the API serves reports supported. The field names a per-capability status so a client can branch on coverage; no other value is emitted."
      },
      "PlatformCapabilities": {
        "type": "object",
        "required": [
          "grade",
          "pnl",
          "strategy",
          "timeline",
          "large_trades",
          "whale_signal",
          "suspicious_trades",
          "insider_radar",
          "market_snapshot"
        ],
        "properties": {
          "grade": {
            "$ref": "#/components/schemas/PlatformCapabilityStatus"
          },
          "pnl": {
            "$ref": "#/components/schemas/PlatformCapabilityStatus"
          },
          "strategy": {
            "$ref": "#/components/schemas/PlatformCapabilityStatus"
          },
          "timeline": {
            "$ref": "#/components/schemas/PlatformCapabilityStatus"
          },
          "large_trades": {
            "description": "The large-trade feed. Canonical key since #16304; whale_signal is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
            "$ref": "#/components/schemas/PlatformCapabilityStatus"
          },
          "whale_signal": {
            "deprecated": true,
            "description": "Deprecated spelling of large_trades, emitted beside it with the same value. Sunset 2027-02-01 (#29352): removed from V1 on that date; read large_trades.",
            "$ref": "#/components/schemas/PlatformCapabilityStatus"
          },
          "suspicious_trades": {
            "$ref": "#/components/schemas/PlatformCapabilityStatus"
          },
          "insider_radar": {
            "deprecated": true,
            "description": "Deprecated spelling of suspicious_trades, emitted beside it with the same value. Sunset 2027-02-01 (#29352): removed from V1 on that date; read suspicious_trades.",
            "$ref": "#/components/schemas/PlatformCapabilityStatus"
          },
          "market_snapshot": {
            "$ref": "#/components/schemas/PlatformCapabilityStatus"
          }
        }
      },
      "Platforms": {
        "type": "object",
        "required": ["platforms"],
        "properties": {
          "platforms": {
            "type": "object",
            "required": ["polymarket"],
            "properties": {
              "polymarket": {
                "$ref": "#/components/schemas/PlatformCapabilities"
              }
            }
          }
        }
      },
      "PositionTimelineEvent": {
        "type": "object",
        "required": [
          "id",
          "event_timestamp",
          "action",
          "outcome_side",
          "token_id",
          "amount_delta",
          "price",
          "usdc_notional",
          "tx_hash",
          "running_amount",
          "running_avg_price"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Opaque fill id (fill_...). Responses before #33245 carried pe_... ids, which no longer match."
          },
          "event_timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp of the on-chain fill."
          },
          "action": {
            "type": "string",
            "enum": ["buy", "sell"],
            "description": "The wallet's own side of this fill: buy or sell."
          },
          "outcome_side": {
            "type": "string",
            "enum": ["yes", "no"]
          },
          "token_id": {
            "type": ["string", "null"],
            "description": "The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets)."
          },
          "amount_delta": {
            "type": "number",
            "description": "Signed share delta (+ on buy, − on sell)."
          },
          "price": {
            "type": "number",
            "description": "Fill price in USDC per share, in [0,1]."
          },
          "usdc_notional": {
            "type": "number",
            "description": "Positive USDC notional of the fill."
          },
          "tx_hash": {
            "type": ["string", "null"],
            "description": "Polygon transaction hash of the fill, from the large-trade alert recorded for it. null for a fill with no such alert: the fill ledger stores no transaction hash (#33245)."
          },
          "running_amount": {
            "type": "number",
            "description": "Cumulative signed stored-fill amount for this outcome after this fill, including older pages. Stable across limits/cursors for unchanged source history. Excludes split, merge, redemption and neg-risk activity; not complete holdings. Incomplete fill history can also leave a negative amount."
          },
          "running_avg_price": {
            "type": "number",
            "description": "Cumulative buy-weighted average of stored fills for this outcome, including older pages; not provider current-position avgPrice. Sells do not change this value. 0 when no stored buys have occurred yet."
          }
        }
      },
      "ExactDecimal": {
        "type": "object",
        "required": ["value", "unit", "scale", "basis"],
        "description": "A lossless decimal atom rendered from the canonical NUMERIC or provider value. The value is a decimal string and must be parsed with a decimal library; it is never a display string and must not be converted through a binary float. `scale` is the source decimal scale. The field is omitted when its source is unavailable.",
        "properties": {
          "value": {
            "type": "string",
            "description": "Plain decimal text at full source precision, including a minus sign for negative values and trailing zeros when the source scale carries them. Parse as an arbitrary-precision decimal.",
            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?$"
          },
          "unit": {
            "type": "string",
            "description": "Unit of the value, such as `USD`, `USD/share`, or `shares`."
          },
          "scale": {
            "type": "integer",
            "minimum": 0,
            "description": "Number of digits after the decimal point in `value`'s source atom."
          },
          "basis": {
            "type": "string",
            "description": "Backend-owned source or derivation basis. Treat it as provenance, not as a display label."
          }
        }
      },
      "PnlCorrection": {
        "type": "object",
        "required": ["basis", "amount", "as_of", "markets_measured"],
        "description": "A derived 0xinsider correction to Polymarket's P&L, never a Polymarket value. Polymarket misbooks neg-risk conversions, in both directions: it puts cost on placeholder YES outcomes minted by a conversion and never books it as a loss (negative amount), and its position records leave out shares the wallet really got, such as YES minted by a conversion, so it books no P&L on them (positive amount). Per neg-risk market the wallet converted in, 0xinsider measures Polymarket's own activity cash against the sum of its position P&L, and sums the difference over every measured market whose shares did not move by direct transfer: transferred shares have no activity row, so such a market keeps Polymarket's figure and is counted in markets_excluded. It is published once every neg-risk market with a sports or esports event that the wallet converted in is measured and checked for transfers, and stays as last published until then; a market with no sports or esports event is not measured, and counts only when it was measured before (on the trader body, pnl.correction_pending says so); a sum under $1 either way publishes nothing. The body's own P&L fields keep Polymarket's figures; this object adds the amount and the corrected figures. Money is truncated toward zero to cents.",
        "properties": {
          "basis": {
            "type": "string",
            "enum": ["neg_risk_conversion_v1"],
            "description": "The correction method."
          },
          "amount": {
            "type": "number",
            "description": "The correction in USD. Negative when Polymarket overstates the wallet."
          },
          "realized": {
            "type": "number",
            "description": "Polymarket's net realized P&L plus amount. Since 2026-10-22 the grade reads this figure's sports and esports share. Omitted when Polymarket's figure is."
          },
          "net_total": {
            "type": "number",
            "description": "Polymarket's net total P&L over every Polymarket market of the wallet, plus amount. Omitted when Polymarket's figure is, and on leaderboard entries."
          },
          "as_of": {
            "type": "string",
            "format": "date-time",
            "description": "The newest measurement among the measured markets."
          },
          "markets_measured": {
            "type": "integer",
            "description": "Neg-risk markets whose measurement amount sums."
          },
          "markets_excluded": {
            "type": "integer",
            "description": "Measured neg-risk markets left out because shares moved in or out of the wallet by direct transfer; they keep Polymarket's figure. Omitted when none."
          }
        }
      },
      "TraderPnlInScope": {
        "type": "object",
        "required": [
          "basis",
          "realized_pnl",
          "markets",
          "markets_resolved",
          "win_rate",
          "markets_out_of_scope",
          "as_of"
        ],
        "description": "A wallet's sports and esports record (#27311). basis names the rule behind realized_pnl (#29370): polymarket_sports_esports_v1 is Polymarket's own realized P&L for the wallet in its sports and esports categories, plus the wallet's maker and taker rebates apportioned by its sports and esports share of its Polymarket volume (by cost while Polymarket reports no overall volume) and the in-scope part of any published neg-risk conversion correction; sports_esports_split_v1, used until both of the wallet's category figures are confirmed, is Polymarket's published wallet-wide realized P&L (with any published correction) split into the part earned on sports and esports markets, with fees, refunds and rebates apportioned by cost. Refreshed after each wallet sync and each read of Polymarket's category leaderboards; as_of dates the market counts.",
        "properties": {
          "basis": {
            "type": "string",
            "description": "The rule behind realized_pnl: polymarket_sports_esports_v1 (Polymarket's sports and esports category figures plus apportioned rebates) or sports_esports_split_v1 (the published realized figure split by cost). A new value means the rule changed; compare figures only within one basis."
          },
          "realized_pnl": {
            "type": ["number", "null"],
            "description": "Sports and esports realized P&L in USD, display-safe. null when the split basis has no published realized figure to split."
          },
          "markets": {
            "type": "integer",
            "description": "Sports and esports markets the wallet has traded, any status."
          },
          "markets_resolved": {
            "type": "integer",
            "description": "Of those, the settled markets: the wallet closed its position by selling out, or the market resolved. Its P&L there is final."
          },
          "win_rate": {
            "type": ["number", "null"],
            "description": "Share of decided sports and esports markets the wallet won, 0 to 1. null with no decided market."
          },
          "markets_out_of_scope": {
            "type": "integer",
            "description": "The wallet's markets outside sports and esports, which 0xinsider no longer lists: those it still stores, those whose rows it deleted and counted, and those of other categories first traded since 2026-10-26, which it does not store and counts as the wallet syncs (#30165)."
          },
          "as_of": {
            "type": "string",
            "format": "date-time",
            "description": "When the record behind these figures was computed."
          }
        }
      },
      "TraderPnlExact": {
        "type": "object",
        "deprecated": true,
        "required": ["realized"],
        "description": "Deprecated since 2026-10-27 and never sent: pnl.exact held the lossless counterpart of the retired wallet-wide pnl.realized (#29830). The member shape below is what the object held before; it is kept so existing type declarations still compile.",
        "properties": {
          "realized": {
            "$ref": "#/components/schemas/ExactDecimal",
            "description": "Native Polymarket realized P&L plus credited maker and taker rebates, with fees included, from the trusted matching `trader_trading_pnl.net_realized_pnl` snapshot."
          }
        }
      },
      "TraderStatsExact": {
        "type": "object",
        "required": ["total_volume"],
        "description": "Lossless counterparts for trader statistics. The object is present exactly when stats.total_volume is.",
        "properties": {
          "total_volume": {
            "$ref": "#/components/schemas/ExactDecimal",
            "description": "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."
          }
        }
      },
      "PositionExact": {
        "type": "object",
        "required": ["shares", "current_value_usd"],
        "description": "Lossless position atoms from `wallet_positions`. `shares` and `current_value_usd` are required when this object is present; other source values are omitted when the mirror has no verified value.",
        "properties": {
          "shares": {
            "$ref": "#/components/schemas/ExactDecimal"
          },
          "cost_basis_usd": {
            "$ref": "#/components/schemas/ExactDecimal"
          },
          "avg_price": {
            "$ref": "#/components/schemas/ExactDecimal",
            "description": "Exact derived price: `wallet_positions.cost_basis_usd / wallet_positions.shares`."
          },
          "current_value_usd": {
            "$ref": "#/components/schemas/ExactDecimal"
          },
          "initial_value_usd": {
            "$ref": "#/components/schemas/ExactDecimal"
          },
          "cash_pnl": {
            "$ref": "#/components/schemas/ExactDecimal"
          },
          "realized_pnl": {
            "$ref": "#/components/schemas/ExactDecimal"
          }
        }
      },
      "Trader": {
        "type": "object",
        "required": ["id", "address", "pnl", "stats", "data_quality"],
        "properties": {
          "id": {
            "type": "string",
            "description": "Prefixed ID (trd_...)."
          },
          "address": {
            "type": "string"
          },
          "username": {
            "type": "string"
          },
          "grade": {
            "type": "string",
            "enum": ["S", "A", "B", "C", "D", "F"]
          },
          "streak_tier": {
            "type": "string",
            "enum": ["hot", "rising", "neutral", "cooling", "cold"],
            "description": "Hot-streak tier (trailing-7d cross-sectional percentile); a separate axis from the all-time grade. Omitted when there is no recent activity."
          },
          "score": {
            "type": "number"
          },
          "forecast_score": {
            "type": "number",
            "description": "Optional forecast score on the documented display scale. Null when unavailable."
          },
          "forecast_evidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Optional measured forecast context. Missing values remain unavailable rather than being inferred."
          },
          "rank": {
            "type": "integer"
          },
          "pnl": {
            "type": "object",
            "properties": {
              "total": {
                "type": "number",
                "deprecated": true,
                "x-never-sent": true,
                "description": "Deprecated since 2026-10-27 and never sent. It was Polymarket's all-time leaderboard P&L, which covered every Polymarket market of the wallet, and wallet figures cover sports and esports markets only (#29830). Read pnl.in_scope.realized_pnl."
              },
              "net_total": {
                "type": "number",
                "deprecated": true,
                "x-never-sent": true,
                "description": "Deprecated since 2026-10-27 and never sent. It was Polymarket's net total P&L over every Polymarket market of the wallet, and wallet figures cover sports and esports markets only (#29830). Read pnl.in_scope.realized_pnl."
              },
              "correction": {
                "$ref": "#/components/schemas/PnlCorrection",
                "deprecated": true,
                "x-never-sent": true,
                "description": "Deprecated since 2026-10-27 and never sent. It was the neg-risk conversion correction to the wallet-wide pnl.net_total and pnl.realized (#29830). Its sports and esports part is inside pnl.in_scope.realized_pnl."
              },
              "correction_pending": {
                "type": "boolean",
                "description": "true while 0xinsider is still checking some of the wallet's converted neg-risk markets with a sports or esports event (not yet measured, measured and not yet checked for transfers, or its latest reads keep failing), so the correction's part inside pnl.in_scope.realized_pnl may change, or arrive where none is published yet. Omitted otherwise."
              },
              "realized": {
                "type": "number",
                "deprecated": true,
                "x-never-sent": true,
                "description": "Deprecated since 2026-10-27 and never sent. It was native Polymarket realized P&L over every Polymarket market of the wallet, and wallet figures cover sports and esports markets only (#29830). Read pnl.in_scope.realized_pnl."
              },
              "unrealized": {
                "type": "number",
                "description": "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."
              },
              "exact": {
                "$ref": "#/components/schemas/TraderPnlExact",
                "deprecated": true,
                "x-never-sent": true,
                "description": "Deprecated since 2026-10-27 and never sent: its one member was the lossless counterpart of the retired pnl.realized (#29830)."
              },
              "in_scope": {
                "$ref": "#/components/schemas/TraderPnlInScope",
                "description": "Additive (#27311): the wallet's sports and esports record, the figure the 0xinsider profile headlines, dated by the sports_record data_quality group. Omitted until 0xinsider has computed the wallet's record; absent means not computed yet, never zero. Also omitted for a wallet that traded no sports or esports market, which never gets a record: then stats.markets_traded is 0 and the sports_record group is partial with owner traders.last_synced (since 2026-10-29, #30589, #30657). Also omitted for a wallet that trades only combos and holds no single sports or esports market: the record counts single markets, so it has none, stats.markets_traded and stats.win_rate are omitted, and the sports_record group is partial with owner traders.last_synced (since 2026-10-29, #30637). Since 2026-10-27 it is the wallet's only P&L figure besides pnl.unrealized (#29830)."
              }
            }
          },
          "stats": {
            "type": "object",
            "description": "Sports and esports markets only since 2026-10-27 (#29830): markets_traded and win_rate come from the wallet's sports and esports record (pnl.in_scope), and total_volume from its stored trade days. A wallet that traded no sports or esports market never gets a record: markets_traded is 0 and win_rate is omitted (since 2026-10-29, #30589, #30657). A wallet that trades only combos has no record either: both are omitted (since 2026-10-29, #30637).",
            "properties": {
              "markets_traded": {
                "type": "integer",
                "description": "Sports and esports markets the wallet traded, any status: pnl.in_scope.markets, dated by the sports_record data_quality group. Omitted until the record is computed. 0 for a wallet that traded no sports or esports market, which never gets a record: at its last completed sync Polymarket counted no market for it, or the sync read its Polymarket positions and found no sports or esports market; none is stored, and no Polymarket sports or esports board lists it; the sports_record group then carries the sync clock (since 2026-10-29, #30589; the second case since #30657). Omitted for a wallet that trades only combos and holds no single sports or esports market, which has no record (since 2026-10-29, #30637). Counted every Polymarket market before 2026-10-27."
              },
              "win_rate": {
                "type": "number",
                "description": "Won over decided sports and esports markets, 0 to 1: pnl.in_scope.win_rate truncated to four places, dated by the sports_record data_quality group. Omitted until the record is computed, while the wallet has no decided sports or esports market, for a wallet that traded no sports or esports market (#30589, #30657), and for one that trades only combos (#30637). Counted every Polymarket market before 2026-10-27."
              },
              "daily_win_rate": {
                "type": "number",
                "deprecated": true,
                "x-never-sent": true,
                "description": "Deprecated since 2026-10-27 and never sent. It counted mark-to-market days over every Polymarket market of the wallet (#29830). Read stats.all.win_days and stats.all.loss_days from GET /api/v1/trader/{address}/pnl, which count sports and esports days."
              },
              "total_volume": {
                "type": "number",
                "description": "Sports and esports USD volume, all time: the sum of every stored trade day's in-scope volume (trader_trade_daily_rollups.in_scope_volume_total), the profile's Volume traded. Dated by the volume data_quality group, which carries the trader sync clock. 0 for a synced wallet with no stored trade day. Omitted before the wallet's first completed sync and while any stored day's in-scope volume is not computed yet, so a partial sum is never served. Polymarket's full-history wallet-wide volume before 2026-10-27 (#29830)."
              },
              "exact": {
                "$ref": "#/components/schemas/TraderStatsExact",
                "description": "Additive lossless counterpart to `total_volume`, present exactly when it is."
              }
            }
          },
          "strategy": {
            "type": "object",
            "required": ["strategy_type"],
            "properties": {
              "strategy_type": {
                "type": "string",
                "description": "Observed trading style identifier. New rows use two_sided, category_focused, high_activity, diversified, mixed, or unclassified, counted over the wallet's sports and esports markets only. Historical identifiers remain readable during normal reclassification; style does not predict skill or intent."
              },
              "description": {
                "type": "string"
              },
              "confidence": {
                "type": "number"
              }
            }
          },
          "category_strengths": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-category rank context when expand=categories is requested. Values include available rank, category totals, performance and record counts; scaled_total_pnl is a legacy alias of total_pnl. Its measurement basis and update timing differ from the plain record returned by GET /api/v1/trader/{address}/categories, so the two need not agree. Use this for rank context and that route for the plain record. Sports and esports only (#28761): keys are sports and esports categories, and a category outside them is omitted, as on that route. The inner key-set is intentionally unconstrained and may contain additional compatibility fields."
          },
          "quant_metrics": {
            "type": "object",
            "deprecated": true,
            "x-never-sent": true,
            "additionalProperties": false,
            "required": [
              "smart_score",
              "copy_score",
              "sharpe_30d",
              "sharpe_7d",
              "profit_factor",
              "edge_consistency",
              "sharpe_percentile",
              "pf_percentile",
              "consistency_percentile"
            ],
            "description": "Deprecated since 2026-10-27 and never sent. These advanced risk and performance metrics covered every Polymarket market of the wallet, and wallet figures cover sports and esports markets only (#29589). expand=quant_metrics is still accepted and adds nothing. For the sports and esports record read pnl.in_scope here, and GET /api/v1/trader/{address}/pnl for its daily series. The member shape below is what the object held before; it is kept so existing type declarations still compile.",
            "properties": {
              "smart_score": {
                "type": ["number", "null"],
                "description": "Trader smart score on a 0..100 display scale; higher is stronger. Null when unavailable."
              },
              "copy_score": {
                "type": ["number", "null"],
                "description": "Copyability score, 0-100. Same base as smart_score minus penalties for traits that make a strategy hard to replicate: -20 if fewer than 50 markets traded, -15 if positions are highly concentrated, -15 if position sizing exceeds about 2x Kelly, -10 if the largest loss on one settled market exceeds 30% of the capital the wallet deployed across all its positions, -10 if edge is inconsistent; result clamped to 0-100. Higher means easier to follow. null when insufficient history."
              },
              "sharpe_30d": {
                "type": ["number", "null"],
                "description": "Sharpe ratio over the trailing 30 days (risk-adjusted return; higher is better). Magnitude can be large for small samples. null when insufficient history."
              },
              "sharpe_7d": {
                "type": ["number", "null"],
                "description": "Sharpe ratio over the trailing 7 days (risk-adjusted return; higher is better). null when insufficient history."
              },
              "profit_factor": {
                "type": ["number", "null"],
                "description": "Gross profit divided by gross loss; greater than 1 is profitable. Capped at 1000 when there are effectively no losses. null when insufficient history."
              },
              "edge_consistency": {
                "type": ["number", "null"],
                "description": "Share of the trader's last 30 days with realized P&L that closed positive, 0-1 (higher is more consistent). A day with no realized P&L is not one of them, so the window can span months. null below 10 such days; null never means 0."
              },
              "sharpe_percentile": {
                "type": ["number", "null"],
                "description": "Cross-sectional percentile rank of the trader's Sharpe ratio versus all traders, 0-100. null when insufficient history."
              },
              "pf_percentile": {
                "type": ["number", "null"],
                "description": "Cross-sectional percentile rank of profit factor versus all traders, 0-100. null when insufficient history."
              },
              "consistency_percentile": {
                "type": ["number", "null"],
                "description": "Cross-sectional percentile rank of edge consistency versus all traders, 0-100. null when insufficient history."
              }
            }
          },
          "last_active": {
            "type": "string",
            "format": "date-time",
            "description": "When the wallet last traded: its most recent recorded trade, the same value the leaderboard entry's last_active carries (which re-reads it hourly). A cached body (meta.cached true) can lag a new trade by up to 60 seconds. No data_quality group dates it: the value is itself a trade time. Since 2026-11-02 (#32324); before, it carried the time 0xinsider last synced the wallet, the same value as synced_at. Omitted when the wallet has no recorded trade."
          },
          "synced_at": {
            "type": "string",
            "format": "date-time",
            "description": "When 0xinsider last completed a sync of the wallet (traders.last_synced), dated by the sync data_quality group. Not when the wallet traded: read last_active for that."
          },
          "sync_status": {
            "type": "string",
            "description": "synced, unknown, or pending."
          },
          "data_quality": {
            "$ref": "#/components/schemas/DataQuality",
            "description": "Data age and coverage for this trader body. Always present. Its six groups are sync (traders.last_synced, covering synced_at and sync_status; it covered last_active until 2026-11-02, #32324, and no group covers last_active now, since the value is itself a trade time), sports_record (trader_product_scope_records.computed_at, covering pnl.in_scope, stats.markets_traded and stats.win_rate: unavailable until the wallet's sports and esports record is computed, partial while it has no decided sports or esports market; for a wallet that traded no sports or esports market, which never gets a record, partial with owner traders.last_synced, as of the completed sync that found none, stats.markets_traded 0 and pnl.in_scope and stats.win_rate omitted, since 2026-10-29, #30589, #30657; for a wallet that trades only combos and holds no single sports or esports market, partial with owner traders.last_synced and all three omitted, since 2026-10-29, #30637), ranking (trader_rankings.computed_at, covering grade, score, streak_tier, forecast_score and forecast_evidence), leaderboard_rank (leaderboard_rank_refresh_state.completed_at, the completion time of the latest fully completed global rank refresh, covering rank), volume (traders.last_synced, covering stats.total_volume, the sum of the trade days the sync stores: unavailable before the first completed sync and while a stored day's sports and esports volume is not computed) and positions (trader_position_snapshots.last_refreshed_at with traders.last_synced as fallback, covering pnl.unrealized, the open-position aggregate). Since 2026-10-27 (#29830) there is no leaderboard_pnl group, and volume is dated by the sync clock instead of trader_usd_volume.observed_at. The positions clock is the latest successful /positions snapshot when one exists, otherwise the last completed trader sync. A rank or position value remains unknown or unavailable when its clock or value is absent. For an unknown wallet every group is unavailable. If the open-position read itself fails, positions is unavailable with a reason that says so, pnl.unrealized is absent, and the body is answered fresh (meta.cached false) and is not kept for later callers."
          },
          "trust": {
            "$ref": "#/components/schemas/TraderTrust",
            "description": "Field-level trust metadata. Present only when expand=trust or expand[]=trust is requested."
          },
          "category_records": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CategorySkillV2"
            },
            "description": "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."
          },
          "category_skill_model": {
            "$ref": "#/components/schemas/CategorySkillModelReadiness"
          },
          "price_edge": {
            "$ref": "#/components/schemas/TraderPriceEdge",
            "description": "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."
          },
          "breakdowns": {
            "$ref": "#/components/schemas/TraderBreakdowns",
            "description": "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."
          }
        }
      },
      "TraderPriceEdge": {
        "type": "object",
        "description": "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.",
        "required": ["markets", "hit_rate", "avg_price", "edge", "status"],
        "properties": {
          "markets": {
            "type": "integer",
            "description": "Settled sports and esports markets of $20 or more at a known entry price that the edge is measured over."
          },
          "hit_rate": {
            "type": "number",
            "description": "Share of those markets whose bought side won, 0-1."
          },
          "avg_price": {
            "type": "number",
            "description": "Mean entry price paid, 0-1."
          },
          "edge": {
            "type": "number",
            "description": "hit_rate minus avg_price, full precision, before any shrink."
          },
          "status": {
            "type": "string",
            "enum": ["ranked", "too_few_markets", "sample_mismatch"],
            "description": "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."
          },
          "shrunk_edge": {
            "type": "number",
            "description": "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."
          },
          "field_average": {
            "type": "number",
            "description": "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."
          }
        }
      },
      "TraderBreakdowns": {
        "type": "object",
        "description": "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.",
        "required": [
          "hourly_performance",
          "time_breakdowns",
          "risk_metrics",
          "entry_price_analysis"
        ],
        "properties": {
          "hourly_performance": {
            "$ref": "#/components/schemas/TraderHourlyPerformance"
          },
          "time_breakdowns": {
            "$ref": "#/components/schemas/TraderTimeBreakdowns"
          },
          "risk_metrics": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TraderRiskMetrics"
              },
              {
                "type": "null"
              }
            ],
            "description": "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."
          },
          "entry_price_analysis": {
            "$ref": "#/components/schemas/TraderEntryPriceAnalysis"
          }
        }
      },
      "TraderHourlyPerformance": {
        "type": "object",
        "description": "P&L and win rate by the UTC hour of the wallet's first trade in each settled sports or esports market.",
        "required": [
          "entries",
          "best_hour",
          "best_win_rate",
          "worst_hour",
          "worst_win_rate",
          "spread_pp",
          "is_approximate"
        ],
        "properties": {
          "entries": {
            "type": "array",
            "description": "One entry per UTC hour that has a settled market; an hour with none is absent.",
            "items": {
              "type": "object",
              "required": ["hour", "markets", "wins", "win_rate", "total_pnl", "avg_pnl"],
              "properties": {
                "hour": {
                  "type": "integer",
                  "description": "UTC hour of the first trade, 0-23."
                },
                "markets": {
                  "type": "integer",
                  "description": "Settled markets first traded in this hour."
                },
                "wins": {
                  "type": "integer",
                  "description": "Of those, the markets that made money at settlement."
                },
                "win_rate": {
                  "type": "number",
                  "description": "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."
                },
                "total_pnl": {
                  "type": "number",
                  "description": "Realized P&L of those markets, USD."
                },
                "avg_pnl": {
                  "type": "number",
                  "description": "total_pnl over markets, USD."
                }
              }
            }
          },
          "best_hour": {
            "type": ["integer", "null"],
            "description": "The hour with the highest win_rate. null when no entry exists."
          },
          "best_win_rate": {
            "type": ["number", "null"],
            "description": "best_hour's win_rate, percentage 0-100. null exactly when best_hour is."
          },
          "worst_hour": {
            "type": ["integer", "null"],
            "description": "The hour with the lowest win_rate. null when no entry exists."
          },
          "worst_win_rate": {
            "type": ["number", "null"],
            "description": "worst_hour's win_rate, percentage 0-100. null exactly when worst_hour is."
          },
          "spread_pp": {
            "type": ["number", "null"],
            "description": "best_win_rate minus worst_win_rate, percentage points. null when either is null."
          },
          "is_approximate": {
            "type": "boolean",
            "description": "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."
          }
        }
      },
      "TraderTimeBreakdowns": {
        "type": "object",
        "description": "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.",
        "required": ["by_duration", "by_hour_bucket", "insights"],
        "properties": {
          "by_duration": {
            "type": "array",
            "description": "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.",
            "items": {
              "$ref": "#/components/schemas/TraderTimeBreakdownBand"
            }
          },
          "by_hour_bucket": {
            "type": "array",
            "description": "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.",
            "items": {
              "$ref": "#/components/schemas/TraderTimeBreakdownBand"
            }
          },
          "insights": {
            "type": "object",
            "description": "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.",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      },
      "TraderTimeBreakdownBand": {
        "type": "object",
        "description": "One band of a time breakdown.",
        "required": [
          "category_value",
          "n_markets",
          "win_rate",
          "expectancy",
          "profit_factor",
          "total_pnl"
        ],
        "properties": {
          "category_value": {
            "type": "string",
            "description": "The band's label."
          },
          "n_markets": {
            "type": "integer",
            "description": "Markets with a realized P&L in the band."
          },
          "win_rate": {
            "type": ["number", "null"],
            "description": "Resolved markets that made money over resolved markets with a nonzero P&L, 0-1. null when none is decided."
          },
          "expectancy": {
            "type": ["number", "null"],
            "description": "total_pnl over n_markets, USD."
          },
          "profit_factor": {
            "type": ["number", "null"],
            "description": "Gross profit over gross loss. null when the band has no loss."
          },
          "total_pnl": {
            "type": ["number", "null"],
            "description": "Realized P&L of the band's markets, USD."
          }
        }
      },
      "TraderRiskMetrics": {
        "type": "object",
        "description": "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.",
        "required": [
          "avg_position_size",
          "median_position_size",
          "max_position_size",
          "position_size_stddev",
          "total_positions",
          "large_position_count",
          "concentration"
        ],
        "properties": {
          "avg_position_size": {
            "$ref": "#/components/schemas/AnalyticNumber",
            "description": "Mean cost basis of a position, USD."
          },
          "median_position_size": {
            "$ref": "#/components/schemas/AnalyticNumber",
            "description": "Median cost basis of a position, USD."
          },
          "max_position_size": {
            "$ref": "#/components/schemas/AnalyticNumber",
            "description": "Largest cost basis of a position, USD."
          },
          "position_size_stddev": {
            "$ref": "#/components/schemas/AnalyticNumber",
            "description": "Population standard deviation of the cost basis, USD."
          },
          "total_positions": {
            "type": "integer",
            "description": "Sports and esports positions with trades."
          },
          "large_position_count": {
            "type": "integer",
            "description": "Positions whose cost is more than twice the mean."
          },
          "concentration": {
            "$ref": "#/components/schemas/AnalyticNumber",
            "description": "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."
          }
        }
      },
      "TraderEntryPriceAnalysis": {
        "type": "object",
        "description": "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.",
        "required": ["buckets", "best_bucket", "worst_bucket", "coverage"],
        "properties": {
          "buckets": {
            "type": "array",
            "description": "One bucket per price band that has a market, in bucket_order.",
            "items": {
              "$ref": "#/components/schemas/TraderEntryPriceBucket"
            }
          },
          "best_bucket": {
            "type": ["string", "null"],
            "description": "The bucket with the highest win rate among buckets of at least 3 markets. null when no bucket has 3."
          },
          "worst_bucket": {
            "type": ["string", "null"],
            "description": "The bucket with the lowest win rate among buckets of at least 3 markets. null when no bucket has 3."
          },
          "coverage": {
            "$ref": "#/components/schemas/TraderEntryPriceCoverage",
            "description": "What the buckets cover (since 2026-11-03, #32671)."
          }
        }
      },
      "TraderEntryPriceCoverage": {
        "type": "object",
        "description": "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.",
        "required": [
          "settled_markets",
          "settled_pnl",
          "bucketed_markets",
          "bucketed_pnl",
          "unbucketed"
        ],
        "properties": {
          "settled_markets": {
            "type": "integer",
            "description": "Settled sports and esports positions: bucketed_markets plus every unbucketed row's markets."
          },
          "settled_pnl": {
            "type": "number",
            "description": "Realized P&L of those positions, USD."
          },
          "bucketed_markets": {
            "type": "integer",
            "description": "Positions in a bucket: the sum of buckets[].markets."
          },
          "bucketed_pnl": {
            "type": "number",
            "description": "Realized P&L of the bucketed positions, USD: the sum of buckets[].total_pnl."
          },
          "unbucketed": {
            "type": "array",
            "description": "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.",
            "items": {
              "$ref": "#/components/schemas/TraderEntryPriceUnbucketed"
            }
          }
        }
      },
      "TraderEntryPriceUnbucketed": {
        "type": "object",
        "description": "Settled positions with no entry-price bucket, for one reason.",
        "required": ["reason", "markets", "total_pnl"],
        "properties": {
          "reason": {
            "type": "string",
            "enum": ["two_sided", "held_side_unpriced", "no_entry_price", "freshness_unknown"],
            "description": "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."
          },
          "markets": {
            "type": "integer",
            "description": "Positions left out for this reason."
          },
          "total_pnl": {
            "type": "number",
            "description": "Their realized P&L, USD."
          }
        }
      },
      "TraderEntryPriceBucket": {
        "type": "object",
        "description": "One entry-price band. Each measure is an analytic value: read state before value.",
        "required": [
          "bucket",
          "bucket_order",
          "markets",
          "wins",
          "win_rate",
          "total_pnl",
          "avg_pnl"
        ],
        "properties": {
          "bucket": {
            "type": "string",
            "description": "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)."
          },
          "bucket_order": {
            "type": "integer",
            "description": "Display position, 0 first, from the lowest price up."
          },
          "markets": {
            "$ref": "#/components/schemas/AnalyticInteger",
            "description": "Markets in the band."
          },
          "wins": {
            "$ref": "#/components/schemas/AnalyticInteger",
            "description": "Of those, the markets that made money."
          },
          "win_rate": {
            "$ref": "#/components/schemas/AnalyticNumber",
            "description": "wins over decided markets (a nonzero P&L), as a percentage 0-100."
          },
          "total_pnl": {
            "$ref": "#/components/schemas/AnalyticNumber",
            "description": "Realized P&L of the band's markets, USD."
          },
          "avg_pnl": {
            "$ref": "#/components/schemas/AnalyticNumber",
            "description": "Mean realized P&L of a market in the band, USD."
          }
        }
      },
      "AnalyticNumber": {
        "type": "object",
        "description": "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.",
        "required": ["state", "source"],
        "properties": {
          "state": {
            "type": "string",
            "enum": [
              "computed",
              "known_zero",
              "not_computed",
              "not_applicable",
              "stale",
              "unavailable",
              "insufficient_data"
            ],
            "description": "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."
          },
          "source": {
            "type": "string",
            "enum": ["provider", "insert_time", "cache", "computed"],
            "description": "Where the value came from, for diagnostics: cache is a stored aggregate, computed a request-time aggregate. Decide on state, not source."
          },
          "value": {
            "type": "number"
          },
          "freshness_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the stored inputs behind the value were written or last confirmed (cache), or the request time (computed)."
          }
        }
      },
      "AnalyticInteger": {
        "type": "object",
        "description": "A computed count with its truth state; the same envelope as AnalyticNumber.",
        "required": ["state", "source"],
        "properties": {
          "state": {
            "type": "string",
            "enum": [
              "computed",
              "known_zero",
              "not_computed",
              "not_applicable",
              "stale",
              "unavailable",
              "insufficient_data"
            ]
          },
          "source": {
            "type": "string",
            "enum": ["provider", "insert_time", "cache", "computed"]
          },
          "value": {
            "type": "integer"
          },
          "freshness_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TraderContext": {
        "type": "object",
        "required": ["trader", "data_as_of", "freshness_note"],
        "properties": {
          "trader": {
            "$ref": "#/components/schemas/Trader"
          },
          "position_summary": {
            "type": "object",
            "description": "Aggregate position and P&L coverage for the trader, over its synced markets. markets_open, unrealized_mtm and cost_basis_locked cover the open positions on sports and esports markets, each market judged when the summary is read (#32119). markets_synced, markets_resolved and the resolved win figures count every stored market: since 2026-10-27 (#29366) those are mostly sports and esports markets, but a market that moved out of sports and esports, or one stored before its category was known, stays in them, and sync_coverage counts every category on both sides. markets_total, total_realized_pnl and synced_realized_pnl still cover every Polymarket market of the wallet. Omitted entirely (key absent, never null) when the trader is not in the local database or native net economics is unavailable. Realized fields remain numbers when present, including a genuine zero.",
            "required": [
              "markets_total",
              "markets_synced",
              "markets_pruned",
              "markets_unstored",
              "markets_combo",
              "markets_resolved",
              "markets_open",
              "sync_coverage",
              "synced_realized_pnl",
              "total_realized_pnl",
              "unrealized_mtm",
              "cost_basis_locked",
              "resolved_win_rate",
              "resolved_wins",
              "resolved_decided",
              "as_of"
            ],
            "properties": {
              "markets_total": {
                "type": ["integer", "null"],
                "description": "Polymarket's count of the markets the wallet traded, every category, when known; null when the provider total is unavailable."
              },
              "markets_synced": {
                "type": "integer",
                "description": "Markets with locally synced position rows."
              },
              "markets_pruned": {
                "type": "integer",
                "description": "Markets outside sports and esports that the wallet traded and whose synced rows 0xinsider deleted, counted when they were deleted (from 2026-10-27, #29366); 0 when none were. Not in markets_synced or any other count here; sync_coverage adds it to markets_synced so both sides of that ratio count every category."
              },
              "markets_unstored": {
                "type": "integer",
                "description": "Markets outside sports and esports that the wallet first traded since 2026-10-26, which 0xinsider does not store, counted as the wallet syncs (#30165); 0 when none are. Not in markets_synced, markets_pruned or any other count here; sync_coverage adds it with markets_pruned to markets_synced."
              },
              "markets_combo": {
                "type": "integer",
                "description": "Combo markets the wallet traded, as maker or taker, counted from the combo fills 0xinsider indexes from the chain (#30218); 0 when it traded none. Polymarket counts each combo as one market in markets_total, and no position read lists one, so a combo is in no other count here; sync_coverage adds it with markets_pruned and markets_unstored to markets_synced."
              },
              "markets_resolved": {
                "type": "integer",
                "description": "Synced markets the wallet has settled: it closed its position by selling out, or the market resolved. Its P&L there is final."
              },
              "markets_open": {
                "type": "integer",
                "description": "Synced sports and esports markets still open with residual value (open positions with current value > 0); a stored market of another category is left out (#32119)."
              },
              "sync_coverage": {
                "type": "number",
                "description": "markets_synced plus markets_pruned plus markets_unstored plus markets_combo, divided by markets_total when the provider total is known (capped at 1.0); 0.0-1.0. Both sides count every category: no Polymarket count of a wallet's sports and esports markets exists, so the ratio does not estimate one. When markets_total is unknown or not positive (null, 0, or negative), this is 1.0 if that sum is positive (else 0.0), so cross-check markets_total before treating 1.0 as full coverage."
              },
              "synced_realized_pnl": {
                "type": "number",
                "x-narrowed": true,
                "description": "Native net realized P&L (USD) over every Polymarket market of the wallet, including credited rebates, minus the stored realized component of synced open positions with positive current value. Rebates are credited to the account, not to a position, so every credited rebate stays in this figure. NUMERIC arithmetic precedes conversion to a JSON number."
              },
              "total_realized_pnl": {
                "type": "number",
                "x-narrowed": true,
                "description": "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."
              },
              "unrealized_mtm": {
                "type": "number",
                "description": "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)."
              },
              "cost_basis_locked": {
                "type": "number",
                "description": "Cost basis (USD) currently tied up in open positions in synced sports and esports markets (#32119)."
              },
              "resolved_win_rate": {
                "type": ["number", "null"],
                "description": "Win rate as a percentage (0-100): resolved_wins over resolved_decided. A settled market that closed at exactly zero realized P&L (a void, a refund, a fully hedged position) is neither a win nor a loss and is not in the denominator, the same rule the leaderboard applies; null when no resolved market was decided. It is the rule of trader.stats.win_rate, read from the synced rows at request time; stats.win_rate is the stored figure the profile shows, refreshed by each sync and a few minutes after a closed-history write. context.md prints one Market win rate, stats.win_rate."
              },
              "resolved_wins": {
                "type": ["integer", "null"],
                "description": "Settled markets that closed at positive realized P&L: the win-rate numerator. Additive; null only on a summary cached before the field existed."
              },
              "resolved_decided": {
                "type": ["integer", "null"],
                "description": "Settled markets that closed at a non-zero realized P&L: the win-rate denominator. At most markets_resolved; the difference is markets settled at exactly zero or with an unknown P&L. Additive; null only on a summary cached before the field existed."
              },
              "as_of": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "RFC3339 freshness of the served OPEN-position data: the trader's latest /positions snapshot, else the last completed sync. The snapshot advances ONLY open positions, so read this as the open-position freshness clock -- the resolved/closed aggregates on this same summary (markets_resolved, resolved_win_rate) advance only on a full sync. The value is the /positions snapshot instant when one exists, so it is typically at or just before the trader-level last sync on a normal sync, and can be AFTER it while the active-view loop refreshes open positions between full syncs. This clock does not establish native accounting freshness. Always present on the wire (serialized as JSON null when the trader has neither a snapshot nor a sync); never omitted."
              }
            }
          },
          "data_as_of": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "RFC3339 freshness of the OPEN-position-level data: when a position_summary is present this mirrors its as_of byte-for-byte (latest /positions snapshot, else last completed sync) -- the open-position freshness clock, since the snapshot advances only open positions; otherwise the trader's last completed sync, even if an unserved position snapshot exists. Null when the selected clock is unavailable; a missing breakdown does not establish position or accounting freshness."
          },
          "freshness_note": {
            "type": "string",
            "description": "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)."
          }
        }
      },
      "Position": {
        "type": "object",
        "required": [
          "id",
          "platform",
          "wallet",
          "side",
          "token_id",
          "shares",
          "current_value_usd",
          "freshness",
          "trader",
          "market"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Composite prefixed ID `pos_<wallet>:<condition_id>:<outcome_index>`."
          },
          "platform": {
            "type": "string",
            "enum": ["polymarket"],
            "description": "Provider discriminator. Polymarket only."
          },
          "wallet": {
            "type": "string",
            "description": "Lowercased proxy wallet address."
          },
          "side": {
            "type": "string",
            "enum": ["YES", "NO"],
            "description": "Binary outcome side. Non-binary positions are not surfaced on V1."
          },
          "token_id": {
            "type": ["string", "null"],
            "description": "The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets)."
          },
          "shares": {
            "type": "number",
            "description": "Live share count from the wallet_positions mirror."
          },
          "avg_price": {
            "type": "number",
            "description": "Volume-weighted entry price for this leg."
          },
          "current_value_usd": {
            "type": "number",
            "description": "Current mark-to-market value in USD (always non-null on V1 — pre-reconcile rows are excluded)."
          },
          "initial_value_usd": {
            "type": "number"
          },
          "cash_pnl": {
            "type": "number",
            "description": "Unrealized P&L for the open position (Polymarket `cashPnl`)."
          },
          "realized_pnl": {
            "type": "number",
            "description": "Closed-leg P&L rolled up (Polymarket `realizedPnl`)."
          },
          "exact": {
            "$ref": "#/components/schemas/PositionExact",
            "description": "Additive lossless source atoms for the display-safe position fields. Parse every `value` with decimal-safe arithmetic; never recover exact values from the numeric twins."
          },
          "last_reconciled_at": {
            "type": "string",
            "format": "date-time",
            "description": "Max updated_at across mirror legs for this pair."
          },
          "freshness": {
            "type": "string",
            "enum": ["fresh", "refreshing", "stale", "unknown"],
            "description": "Backend-computed staleness bucket derived from last_reconciled_at."
          },
          "trader": {
            "type": "object",
            "required": ["id", "address", "is_new_wallet"],
            "properties": {
              "id": {
                "type": "string",
                "description": "Prefixed ID (`trd_...`)."
              },
              "address": {
                "type": "string"
              },
              "username": {
                "type": "string"
              },
              "grade": {
                "type": "string",
                "enum": ["S", "A", "B", "C", "D", "F"]
              },
              "win_rate": {
                "type": "number",
                "description": "Sports and esports win rate as a ratio from 0 to 1 (0.62 means 62%): wins over the decided sports and esports markets on the wallet's record, the same figure as pnl.in_scope.win_rate and stats.win_rate on GET /api/v1/trader/{address}. Since 2026-10-27 it no longer counts other markets (#29953). Absent when the wallet has no record or no decided market."
              },
              "pnl": {
                "type": "number",
                "deprecated": true,
                "x-never-sent": true,
                "description": "Deprecated since 2026-10-27 and never sent. It was Polymarket's net total P&L over every Polymarket market of the wallet, and wallet figures cover sports and esports markets only (#29953). Read trader.in_scope_realized_pnl."
              },
              "in_scope_realized_pnl": {
                "type": "number",
                "description": "The wallet's realized P&L in USD on sports and esports markets, the figure the 0xinsider profile shows: the record behind pnl.in_scope.realized_pnl on GET /api/v1/trader/{address}, to cents. For a graded wallet it is read from the latest grading pass, so it can trail that figure until the next pass. Omitted until 0xinsider has computed the wallet's record (#29953)."
              },
              "markets": {
                "type": "integer",
                "description": "Sports and esports markets on the wallet's record, pnl.in_scope.markets on GET /api/v1/trader/{address}. Since 2026-10-27 it no longer counts other markets (#29953). Absent when the wallet has no record."
              },
              "wallet_age_days": {
                "type": "number",
                "description": "Days since the wallet's first-seen time. For a wallet 0xinsider first recorded on or after March 21, 2026, that is when 0xinsider recorded it. For a wallet recorded earlier, it is usually the wallet's first Polymarket activity, so the age can run to years. It is not the wallet's on-chain age or the time of its first trade. Absent when the first-seen time is unknown."
              },
              "is_new_wallet": {
                "type": "boolean",
                "description": "True when wallet_age_days is under the new-wallet threshold (30 days), which means 0xinsider first recorded the wallet in the last 30 days. False when wallet_age_days is absent. This public V1 field is first-seen recency, not the wallet's on-chain age."
              }
            }
          },
          "market": {
            "type": "object",
            "required": ["id", "condition_id", "title"],
            "properties": {
              "id": {
                "type": "string",
                "description": "Prefixed ID (`mkt_...`)."
              },
              "condition_id": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "slug": {
                "type": "string"
              },
              "event_slug": {
                "type": "string"
              },
              "category": {
                "type": "string",
                "description": "Provider-backed market_canonical category."
              },
              "outcome_label": {
                "type": "string",
                "description": "Provider-reported outcome label (e.g. team name for sports). Separate from `side` because provider labels can diverge from the binary Yes/No axis."
              },
              "end_date": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        }
      },
      "LargeTrade": {
        "type": "object",
        "required": [
          "id",
          "traded_at",
          "size_usd",
          "side",
          "outcome",
          "token_id",
          "price",
          "review_score",
          "signal_score",
          "recorded_review_score",
          "recorded_signal_score",
          "suspicion_score",
          "suspicion_track",
          "trader",
          "market",
          "clv"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Prefixed ID (wt_...)."
          },
          "traded_at": {
            "type": "string",
            "format": "date-time"
          },
          "size_usd": {
            "type": "number"
          },
          "side": {
            "type": "string",
            "enum": ["BUY", "SELL"]
          },
          "outcome": {
            "type": ["string", "null"],
            "description": "Traded outcome label (e.g. \"Yes\"/\"No\"/team name), resolved provider-first from the trade's outcome_index against market_canonical (index 0 -> yes, 1 -> no). Distinct axis from side (BUY/SELL): side is the trade direction, outcome is which leg was traded. null for multi-outcome (outcome_index >= 2) or unsynced markets, and for a Polymarket trade recorded before 2026-04-02T00:00:00Z unless its stored outcome_index was verified against the fill's own trade records (before that date the stored index was wrong for a large share of trades; an unverified side is unknown, not defaulted)."
          },
          "token_id": {
            "type": ["string", "null"],
            "description": "The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the traded outcome; null when unavailable (e.g. unsynced markets) and for a Polymarket trade recorded before 2026-04-02T00:00:00Z whose traded side is not verified (the same rule as outcome)."
          },
          "price": {
            "type": "number"
          },
          "review_score": {
            "type": "number",
            "description": "Current trade review score on a 0..1 scale; higher values indicate a stronger review signal. This is the current response value and can differ from the recorded score. Missing measurements remain unavailable."
          },
          "signal_score": {
            "deprecated": true,
            "type": "number",
            "description": "Deprecated alias of review_score with the same current value and 0..1 scale. Sunset 2027-02-01 (#29352): removed from V1 on that date; read review_score."
          },
          "recorded_review_score": {
            "type": ["number", "null"],
            "description": "0.0–1.0 review score written once when the trade row is inserted, from the trader's statistics at that moment. Populated from 2026-08-03T11:59Z; older rows return null and are never backfilled, because a backfill could only read today's statistics. If a trade is added later, its time-sensitive recorded score reflects that delay. Canonical since #16311; recorded_signal_score carries the same value."
          },
          "recorded_signal_score": {
            "deprecated": true,
            "type": ["number", "null"],
            "description": "0.0–1.0 review score written once when the trade row is inserted; null before 2026-08-03T11:59Z. Deprecated (#16311): `recorded_review_score` is the canonical spelling and carries the same value; this key stays on the wire until its sunset on 2027-02-01 (#29352), when it is removed."
          },
          "suspicion_score": {
            "type": ["integer", "null"],
            "minimum": 0,
            "maximum": 100,
            "description": "Persisted live suspicion score from the scorer. Null when the row has no persisted score."
          },
          "suspicion_track": {
            "type": ["string", "null"],
            "enum": ["whale", "fresh_conviction", "sliced_position", null],
            "description": "Persisted scorer track. Null when a legacy row has no stored track label."
          },
          "market_volume_share": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "This fill's size relative to its market: its share count (size_usd / price) divided by the shares the market has traded, Polymarket's recorded volume, which counts shares rather than dollars, as observed at or after the trade, so the value always falls between 0 and 1 inclusive. A 20,000-share fill is 0.00005 of a market that has traded 400M shares and 0.125 of one that has traded 160,000, which size_usd alone cannot distinguish. Absent when no volume figure recorded at or after the trade is available, or when that figure is smaller than the fill; never 0 as a stand-in and never capped at 1, because a denominator we cannot trust publishes nothing rather than a trimmed number. A market's volume keeps growing, so the same trade reports a smaller share as the market trades on."
          },
          "trader": {
            "type": "object",
            "required": ["id", "address", "grade_at_trade", "grade_at_trade_status"],
            "properties": {
              "id": {
                "type": "string"
              },
              "address": {
                "type": "string"
              },
              "username": {
                "type": "string"
              },
              "grade": {
                "type": "string",
                "description": "The trader's grade today, on every row however old. For what the grade was when the trade happened, read grade_at_trade.",
                "enum": ["S", "A", "B", "C", "D", "F"]
              },
              "grade_at_trade": {
                "type": ["string", "null"],
                "enum": ["S", "A", "B", "C", "D", "F", null],
                "description": "The grade the trader held when the trade happened, from recorded grade history (recorded from 2026-09-19T23:00Z). Null unless grade_at_trade_status is graded. Never today's grade projected backward."
              },
              "grade_at_trade_status": {
                "type": "string",
                "enum": ["graded", "ungraded", "unknown"],
                "description": "graded: grade_at_trade holds the recorded grade. ungraded: the trader was recorded without a grade at that moment. unknown: no record covers the moment, which is every trade before 2026-09-19T23:00Z and a trade that fell between a grade change and its confirmation. unknown never means ungraded."
              }
            }
          },
          "market": {
            "type": "object",
            "required": ["id", "condition_id", "title"],
            "properties": {
              "id": {
                "type": "string"
              },
              "condition_id": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "slug": {
                "type": "string"
              },
              "category": {
                "type": "string",
                "description": "Provider-backed market_canonical category."
              }
            }
          },
          "clv": {
            "type": "object",
            "required": [
              "status",
              "unavailable_reason",
              "pre_kickoff",
              "close_anchor_at",
              "close_price",
              "clv_cents",
              "basis_version",
              "taker_fee_cents",
              "clv_after_fees_cents"
            ],
            "properties": {
              "basis_version": {
                "type": "string",
                "description": "The CLV definition, clv@v1."
              },
              "close_anchor_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "The anchor pre_kickoff was judged against: the stored close's anchor, else the market's kickoff."
              },
              "close_price": {
                "type": ["number", "null"],
                "description": "The traded outcome's closing price, 0 to 1, whenever a usable close is stored and the outcome is known, in play included."
              },
              "clv_cents": {
                "type": ["number", "null"],
                "description": "Cents per share, positive when the trade beat the close: buy is (close_price - price) * 100, sell is (price - close_price) * 100. Gross of fees. Computed from the trade's exact stored price; price on the wire is rounded to 4 places, so a recomputation from it agrees within 0.005 cents. Set exactly when status is measured."
              },
              "pre_kickoff": {
                "type": ["boolean", "null"],
                "description": "Whether the trade filled before close_anchor_at. null when the market has no anchor."
              },
              "status": {
                "type": "string",
                "enum": ["measured", "in_play", "pending", "unavailable"],
                "description": "measured: clv_cents is set. in_play: traded at or after the close anchor (kickoff), no CLV is defined. pending: traded before kickoff and the market's close is not stored yet. unavailable: see unavailable_reason."
              },
              "unavailable_reason": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "no_observation_in_lookback",
                      "provider_empty_window",
                      "provider_invalid_contract",
                      "capture_window_closed",
                      "no_game_start_time",
                      "not_one_sided_resolution",
                      "not_captured",
                      "close_token_mismatch",
                      "anchor_stale",
                      "outcome_unknown"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Set exactly when status is unavailable. The market's reasons (see MarketClose.unavailable_reason), plus anchor_stale (the kickoff moved after the close was captured) and outcome_unknown (the traded outcome is not known for this trade)."
              },
              "clv_after_fees_cents": {
                "type": ["number", "null"],
                "description": "clv_cents - taker_fee_cents: the CLV after the fee the fill paid, cents per share. Set exactly when both are set."
              },
              "taker_fee_cents": {
                "type": ["number", "null"],
                "description": "The fee the fill paid as taker, cents per share, from the exchange's on-chain record of the fill (the OrderFilled event in its Polygon receipt); the trader is its taker. Polymarket charges only takers, so a buy's fee adds to its cost and a sell's comes out of its proceeds, and either way it lowers the CLV by this amount. Includes any builder fee an app added; excludes maker and taker rebates, which Polymarket pays later and no fill records. Set whatever status is; null until the record is decoded (about a minute after the trade) and for trades before 2026-08-16."
              }
            },
            "description": "Closing line value against the market's stored close (GET /api/v1/market/{condition_id}/close). Always present; status says whether it is measured."
          }
        }
      },
      "CounterpartyMatchBreakdown": {
        "type": "object",
        "required": ["match_type", "maker_fill_count", "filled_shares"],
        "properties": {
          "match_type": {
            "type": "string",
            "enum": ["COMPLEMENTARY", "MINT", "MERGE"]
          },
          "maker_fill_count": {
            "type": "integer"
          },
          "filled_shares": {
            "type": "string",
            "description": "Exact decimal shares."
          }
        }
      },
      "CounterpartyParticipant": {
        "type": "object",
        "required": [
          "counterparty_key",
          "execution_wallet",
          "identity_status",
          "maker_fill_count",
          "filled_shares",
          "filled_usdc",
          "share_pct",
          "match_breakdown"
        ],
        "properties": {
          "counterparty_key": {
            "type": "string"
          },
          "execution_wallet": {
            "type": "string",
            "description": "Lowercase Polygon wallet from the exact OrderFilled log."
          },
          "identity_status": {
            "type": "string",
            "enum": ["resolved", "infrastructure", "unavailable"]
          },
          "resolved_user_id": {
            "type": "string"
          },
          "wallet_family": {
            "type": "string"
          },
          "resolution_block": {
            "type": "integer"
          },
          "resolution_source": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "grade": {
            "type": "string"
          },
          "last_traded_at": {
            "type": "string",
            "format": "date-time",
            "description": "Latest nonfuture recorded wallet-wide trade time for the tracked trader supplying this participant's grade. Omitted when unavailable; not the receipt time or the owner EOA's activity. Trader context is read with the response and is not frozen by execution membership snapshots."
          },
          "profile_segment": {
            "type": "string",
            "description": "0xinsider profile path segment for this participant, present only when the execution wallet has a tracked trader: `@<username>` when that username resolves to the trader alone, otherwise the trader's lowercase wallet. Percent-encode the part after `@` and append to `https://0xinsider.com/profile/`."
          },
          "maker_fill_count": {
            "type": "integer"
          },
          "filled_shares": {
            "type": "string",
            "description": "Exact decimal shares."
          },
          "filled_usdc": {
            "type": "string",
            "description": "Exact decimal USDC amount."
          },
          "share_pct": {
            "type": "string",
            "description": "Participant share of the exact execution, from 0 through 100."
          },
          "match_breakdown": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CounterpartyMatchBreakdown"
            }
          }
        }
      },
      "CounterpartyExecution": {
        "type": "object",
        "required": [
          "execution_id",
          "exchange_family",
          "transaction_hash",
          "orders_matched_log_index",
          "taker",
          "makers"
        ],
        "properties": {
          "execution_id": {
            "type": "string"
          },
          "exchange_family": {
            "type": "string",
            "enum": ["ctf_v2", "neg_risk_ctf_v2", "exchange_v3"],
            "description": "Polymarket exchange contract that emitted the execution: `ctf_v2` the CTF Exchange v2, `neg_risk_ctf_v2` the Neg Risk CTF Exchange v2, `exchange_v3` ExchangeV3, which settles Polymarket Protocol V2 binary and neg-risk markets. Treat an unknown value as another exchange."
          },
          "transaction_hash": {
            "type": "string"
          },
          "orders_matched_log_index": {
            "type": "integer"
          },
          "taker": {
            "$ref": "#/components/schemas/CounterpartyParticipant"
          },
          "makers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CounterpartyParticipant"
            }
          },
          "makers_next_cursor": {
            "type": "string",
            "description": "Stable cursor after the last maker included in the bounded inline page."
          }
        }
      },
      "CounterpartyAnalysis": {
        "type": "object",
        "required": [
          "status",
          "execution_count",
          "available_execution_count",
          "unavailable_execution_count",
          "executions"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["available", "partial", "unavailable"]
          },
          "unavailable_reason": {
            "type": "string"
          },
          "snapshot_id": {
            "type": "string",
            "description": "Deterministic immutable membership snapshot for this detail response."
          },
          "analysis_id": {
            "type": "string",
            "description": "Stable digest binding page cursors to one snapshot and execution set."
          },
          "execution_count": {
            "type": "integer"
          },
          "available_execution_count": {
            "type": "integer"
          },
          "unavailable_execution_count": {
            "type": "integer"
          },
          "executions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CounterpartyExecution"
            }
          },
          "executions_next_cursor": {
            "type": "string",
            "description": "Stable cursor after the last execution included in the bounded inline page."
          }
        }
      },
      "CounterpartyMakerPage": {
        "type": "object",
        "required": ["analysis_id", "snapshot_id", "execution_id", "items"],
        "properties": {
          "analysis_id": {
            "type": "string"
          },
          "snapshot_id": {
            "type": "string"
          },
          "execution_id": {
            "type": "string"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CounterpartyParticipant"
            }
          },
          "next_cursor": {
            "type": "string",
            "description": "Cursor bound to the analysis, execution, last full-denominator share total, and wallet."
          }
        }
      },
      "LargeTradeDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/LargeTrade"
          },
          {
            "type": "object",
            "required": ["counterparty_analysis"],
            "properties": {
              "counterparty_analysis": {
                "$ref": "#/components/schemas/CounterpartyAnalysis"
              }
            }
          }
        ]
      },
      "PickHolder": {
        "type": "object",
        "required": ["address", "name", "grade", "last_traded_at", "shares"],
        "properties": {
          "address": {
            "type": "string"
          },
          "name": {
            "type": ["string", "null"]
          },
          "grade": {
            "type": ["string", "null"],
            "description": "All-time trader grade (S, A, B, C, D, F)."
          },
          "last_traded_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "The wallet's most recent recorded trade time, stamped at serve time from its current trader record rather than frozen with the pick. Always sent; null when no trade time is recorded."
          },
          "profile_segment": {
            "type": "string",
            "description": "0xinsider profile path segment this wallet links to: `@<username>` when that username resolves to this wallet alone, otherwise the lowercase wallet. Percent-encode the part after `@` and append to `https://0xinsider.com/profile/`. Stamped at serve time; absent on a body cached before the field shipped."
          },
          "shares": {
            "type": "number"
          },
          "entry_value_usd": {
            "type": "number",
            "description": "USD entry value of this wallet's position: `shares` times the pick's frozen `backed_price`. An entry valuation, never a live balance or the provider's current value. Omitted when the holder snapshot has no valid price."
          },
          "category_win_rate": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "This wallet's win rate in the pick's canonical category bucket (the pick's `category` field, e.g. Basketball -- label the rate with it, never with the narrower `display_category` league, except when `category_win_rate_game` is present, in which case the rate is that game's or league's and is labelled with it): the share of the wallet's settled markets in that category (it closed its position by selling out, or the market resolved) whose realized P&L closed positive, as a 0..1 fraction. Present only with `category_win_rate_status` = `measured`, on `display_holders` entries, and only when the wallet clears the settled-market floor; recomputed at serve time from the current category read model, not frozen with the pick. Absent on `holders` entries, legacy rows, and payloads predating the field."
          },
          "category_win_record": {
            "type": "object",
            "required": ["wins", "decided"],
            "properties": {
              "wins": {
                "type": "integer",
                "minimum": 0,
                "description": "Settled markets in the category that this wallet closed with a profit."
              },
              "decided": {
                "type": "integer",
                "minimum": 0,
                "description": "Settled markets in the category that this wallet closed with a profit or a loss. A market resolved at zero realized P&L is in neither count."
              }
            },
            "description": "The two counts `category_win_rate` is the ratio of, read from the same row: `wins / decided` equals the rate. Counts every settled Polymarket market the wallet traded (it closed its position by selling out, or the market resolved) in the pick's canonical category (or in its game or league, when `category_win_rate_game` is present), at any position size; the counts are rebuilt daily. Present only with `category_win_rate_status` = `measured`; absent otherwise and on payloads predating the field."
          },
          "category_avg_price": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "The wallet's average entry price in the pick's canonical category, as a 0..1 fraction of $1 (0.98 is 98 cents). Its sample is the wallet's markets in that category that resolved to a winning side, of $20 or more where it bought one side at a known price, so it can differ from the `category_win_record` sample. A wallet that buys near-certain outcomes wins almost every time, so read the win rate beside this price. Present only with `category_win_rate_status` = `measured`, and only when that sample has at least 5 markets. When `category_win_rate_game` is present the price is still the whole `category` bucket's: this field has no per-game or per-league price. Absent otherwise and on payloads predating the field."
          },
          "category_win_rate_game": {
            "type": "string",
            "description": "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."
          },
          "category_win_rate_status": {
            "type": "string",
            "enum": ["measured", "not_enough_data", "unavailable", "untracked"],
            "description": "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."
          },
          "wallet_age_days": {
            "type": ["number", "null"],
            "description": "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."
          },
          "is_new_wallet": {
            "type": "boolean",
            "description": "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."
          },
          "markets_traded": {
            "type": ["integer", "null"],
            "description": "Distinct markets this wallet has traded. 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."
          },
          "is_bot": {
            "type": "boolean",
            "description": "True when the wallet has traded 10,000 or more distinct markets, the breadth floor 0xinsider uses to mark automated wallets. It is a breadth rule, not proof of automation. 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."
          },
          "x_username": {
            "type": ["string", "null"],
            "description": "The wallet's X handle from its Polymarket profile, normalized to 1-15 characters of [A-Za-z0-9_] with no `@`. Link it as `https://x.com/<handle>`. 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."
          }
        }
      },
      "ScheduledPickSlot": {
        "type": "object",
        "description": "An entitled same-day slot with a future scheduled release: stable identity and backend-owned release/kickoff instants. It leaves this list at its release instant; an unpublished slot is never a delayed recommendation. No matchup, category, platform, side, price, or holder fields appear before release. Unauthorized scheduled ranks appear only in locked_picks.",
        "required": [
          "pick_rank",
          "release_at",
          "kickoff",
          "pick_id",
          "publication_order",
          "is_free_selection",
          "supersedes_pick_id"
        ],
        "properties": {
          "pick_rank": {
            "type": "integer",
            "minimum": 1,
            "maximum": 30,
            "description": "Deprecated compatibility daily release slot; use pick_id for identity and publication_order for scheduling.",
            "deprecated": true
          },
          "release_at": {
            "type": "string",
            "format": "date-time",
            "description": "The slot's future release instant. Remove this preview at that instant and read again for published picks; a scheduled slot does not guarantee publication."
          },
          "kickoff": {
            "type": "string",
            "format": "date-time",
            "description": "The backed game's current kickoff instant."
          },
          "pick_id": {
            "type": "string",
            "pattern": "^[1-9][0-9]*$",
            "description": "Stable pick row identity as decimal text. Never use a quality rank as identity."
          },
          "publication_order": {
            "type": "integer",
            "description": "Compatibility release slot. No quality claim; historic scheduling order is retained."
          },
          "is_free_selection": {
            "type": "boolean",
            "description": "Viewer-independent free selection designation. New rows store it explicitly; historic null storage uses the original free slot."
          },
          "supersedes_pick_id": {
            "deprecated": true,
            "type": ["string", "null"],
            "pattern": "^[1-9][0-9]*$",
            "description": "Deprecated (#24157): always null. No replacement lineage was ever recorded in this field; the key stays so existing V1 clients keep parsing. Identify a pick by pick_id."
          }
        }
      },
      "PickOfTheDay": {
        "type": "object",
        "required": ["state", "supersedes_pick_id"],
        "properties": {
          "state": {
            "type": "string",
            "enum": ["full"],
            "description": "Full success containing entitled proof-readable picks."
          },
          "pick_date": {
            "type": "string",
            "format": "date",
            "description": "The pick's local publication date (YYYY-MM-DD)."
          },
          "pick_rank": {
            "type": "integer",
            "minimum": 1,
            "maximum": 30,
            "description": "Deprecated compatibility daily release slot; use pick_id for identity and publication_order for scheduling.",
            "deprecated": true
          },
          "picks": {
            "type": "array",
            "description": "Published picks for this product day in the returned display order. Use pick_id for identity.",
            "items": {
              "$ref": "#/components/schemas/PickOfTheDay"
            }
          },
          "pick_count": {
            "type": "integer",
            "minimum": 0,
            "maximum": 25,
            "description": "Number of items in `picks`: the proof-readable picks. Picks held in `proof_pending_picks` are not counted."
          },
          "scheduled_picks": {
            "type": "array",
            "description": "Rank-ordered entitled selections that have not released. Every row retains release_at and kickoff; unauthorized scheduled ranks appear only in identity-free locked_picks.",
            "items": {
              "$ref": "#/components/schemas/ScheduledPickSlot"
            }
          },
          "matchup": {
            "type": "string",
            "description": "Human-readable matchup (e.g. \"Portugal vs. Uzbekistan\")."
          },
          "category": {
            "type": "string",
            "description": "Recorded canonical sport category. Prefer display_category for the public competition label."
          },
          "display_category": {
            "type": "string",
            "description": "Frozen public presentation category. Tennis uses the provider-verified ATP or WTA tour, including Wimbledon and doubles; unknown tours retain Tennis. Every men's and women's cricket competition uses Cricket. Other sports use the curated league, esports title or soccer competition label, then the provider series name without its season year, then category when no competition is known. The canonical category and measured cohort are unchanged: an esports title still uses the pooled Esports category. Optional for mixed-version client compatibility."
          },
          "platform": {
            "type": "string",
            "enum": ["polymarket"],
            "description": "Provider platform. Always polymarket."
          },
          "release_at": {
            "type": "string",
            "format": "date-time",
            "description": "The pick's stored release instant. Use the returned timestamp; published_at records when publication occurred."
          },
          "is_locked": {
            "type": "boolean",
            "description": "True only before the pick's stored release instant (a pre-release embargo flag); effectively always false on a served, already-published pick. To detect that the backed game has kicked off, use `game_started`."
          },
          "game_started": {
            "type": "boolean",
            "description": "True once the backed game's kickoff has passed (kickoff <= now). When true the snapshotted pre-game price is no longer actionable. Absent for a legacy pick with no stored kickoff (treat as not-started)."
          },
          "game_ended": {
            "type": "boolean",
            "description": "Whether the backed game is over according to the cached live scoreboard, read at serve time. Tells a finished game from one still in play before `outcome` settles. Omitted when the pick has no event slug or no scoreboard is cached for it; absence is unknown, never false."
          },
          "outcome": {
            "type": "string",
            "enum": ["pending", "win", "loss", "void"],
            "description": "Settlement outcome of the backed side; 'pending' until the market resolves."
          },
          "outcome_display": {
            "type": "string",
            "description": "Pre-formatted SETTLEMENT STATUS for display: \"Win\" / \"Loss\" / \"Void\" / \"Pending\" -- the outcome enum above as a label. Convenience only; outcome is the source value. NOTE: this is the win/loss STATUS, not the backed side. The backed side is pick_outcome_label (\"Belgium (-2.5)\") -- a different field answering a different question."
          },
          "pick_outcome_label": {
            "type": "string",
            "description": "The backed side phrased as a bet: a team for a moneyline (e.g. \"Portugal\"), the handicap line for a spread (e.g. \"Belgium (-2.5)\"), or \"{team} to advance\" for a knockout advancement market (e.g. \"Spain to advance\")."
          },
          "token_id": {
            "type": "string",
            "description": "The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the backed outcome; omitted when unavailable (e.g. unsynced markets)."
          },
          "position": {
            "type": "string",
            "description": "The backed side phrased as a bet (e.g. \"Portugal to win\")."
          },
          "side_summary": {
            "type": "string",
            "description": "One-line summary of which side sharp money is backing. Required on every item in `picks`: a current-day published pick whose required holder proof is not safely readable is listed in `proof_pending_picks` instead of being served with a partial success shape or a synthetic zero, and the route returns 503 read_model_warming only when no published pick has readable proof."
          },
          "sharp_wallet_count": {
            "type": "integer",
            "description": "S/A wallet count on the backed side in the public V1 compatibility projection."
          },
          "smart_wallet_count": {
            "type": "integer",
            "deprecated": true,
            "description": "Deprecated spelling of sharp_wallet_count with the same value."
          },
          "top_grade": {
            "type": "string",
            "description": "Best recorded S/A grade in the public V1 compatibility projection."
          },
          "sharp_usd": {
            "type": "number",
            "description": "Recorded sharp-money magnitude in USD when available."
          },
          "smart_usd": {
            "type": "number",
            "deprecated": true,
            "description": "Deprecated spelling of sharp_usd with the same value."
          },
          "backed_price": {
            "type": "number",
            "description": "Frozen pre-game probability (0..1) for the backed side, written once at publication. It is the Polymarket CLOB order book midpoint at release, not an executed fill: a buyer lifts the ask, so a subscriber's own entry is usually a little worse than this price."
          },
          "entry_price_note": {
            "type": "string",
            "description": "Full-only disclosure when backed_price was recovered from provider history within 30 seconds before publication. Render beside the price. Absent for ordinary publication captures and teasers; this is a historical reference, not an executed fill."
          },
          "odds_display": {
            "type": "string",
            "description": "Pre-formatted backed_price as cents-on-the-dollar odds, to ONE decimal: \"62.0c\" / \"99.9c\". Never rounded to a whole cent -- a 99.9c favorite is not a 100c certainty. Convenience only; backed_price is the source value. Omitted when backed_price is."
          },
          "stake_usd": {
            "type": "number",
            "description": "The flat stake the published record puts on every pick, in USD: 1000 since 2026-09-22 (it was 100 before). Present exactly when return_usd is, so a reader never has to know the stake from anywhere else."
          },
          "return_usd": {
            "type": "number",
            "description": "Gross return of stake_usd at the frozen midpoint price (stake_usd / backed_price). A real fill pays the ask, so an executed stake usually returns a little less. Omitted with backed_price."
          },
          "return_per_100": {
            "type": "number",
            "description": "The same return on a literal $100 (100 / backed_price), kept for compatibility: the field predates stake_usd and its name promises the $100 basis, so a client that scales it to its own stake stays right. Present exactly when return_usd is."
          },
          "payout_display": {
            "type": "string",
            "description": "Pre-formatted return_usd as USD with cents and thousands separators: \"$1,612.90\" / \"$12,500.00\". The GROSS return (the stake included), so it carries no sign. Convenience only; return_usd is the source value. Omitted when return_usd is."
          },
          "profit_display": {
            "type": "string",
            "description": "Pre-formatted PROFIT on the stake -- return_usd minus stake_usd, i.e. the payout net of what you put in -- as a signed USD string: \"+$612.90\". Distinct from payout_display, which is gross. Omitted when return_usd is."
          },
          "clv_status": {
            "type": "string",
            "description": "Backend-owned CLV capture disposition. \"pending\" means no capture decision exists yet; terminal provider or quality statuses remain distinguishable. The raw close price and timestamp are never serialized."
          },
          "clv_basis": {
            "type": "string",
            "description": "Backend-owned CLV evidence basis. `frozen_displayed_entry` uses the persisted displayed entry. `historical_provider_entry` uses a known-CLOB point at or before publication. `historical_provider_price_match` requires the latest point in the prior hour to match. `historical_provider_nearby_price_match` requires a matching point within five minutes before publication. Source-null bases preserve unknown original provenance."
          },
          "clv_pct": {
            "type": "number",
            "description": "Closing-line value toward the backed side, computed as (close / entry - 1) * 100. The basis-specific provider p entry must match the stored display; historical_provider_price_match also requires source provenance to remain null and its latest entry to be within the one-hour window at or before publication. Every basis requires a later quality-checked p close from the same series in the bounded post-entry, pre-kickoff window. Omitted when not measured."
          },
          "clv_display": {
            "type": "string",
            "description": "Backend-formatted signed CLV percentage, present exactly when clv_pct is present."
          },
          "clv_explanation": {
            "type": "string",
            "description": "Backend-owned CLV formula text with the entry probability, close probability, and rounded result. Provider timestamps remain private."
          },
          "unit_score": {
            "type": "number",
            "description": "Net return for the pick in stake units (return_usd / stake_usd - 1); one unit is one stake_usd stake, and the figure is the same under any stake size. Omitted when the outcome is not valued."
          },
          "unit_score_display": {
            "type": "string",
            "description": "Backend-formatted signed unit score, present exactly when unit_score is present."
          },
          "sharp_pct": {
            "type": "number",
            "description": "Recorded sharp-money share as a 0..1 fraction when available. This is not a winning probability."
          },
          "market_pct": {
            "type": "number",
            "description": "Recorded market-implied probability as a 0..1 fraction when available."
          },
          "qualifying_expert": {
            "type": "object",
            "description": "Optional recorded specialist facts on a full response. These describe the trader, not the pick's win probability. Omitted when no recorded specialist is available.",
            "properties": {
              "address": {
                "type": "string",
                "description": "Trader wallet address."
              },
              "name": {
                "type": ["string", "null"],
                "description": "Provider display name, or null for an unnamed wallet."
              },
              "grade": {
                "type": ["string", "null"],
                "description": "Recorded trader grade. Public V1 preserves its S/A compatibility projection."
              },
              "canonical_category": {
                "type": "string",
                "description": "The canonical sport bucket the win rate was measured over (for example Basketball). Can be BROADER than the pick's display_category, which names an exact league such as NBA — label the rate with this field, never with display_category."
              },
              "win_rate": {
                "type": ["number", "null"],
                "description": "Share of the trader’s settled markets in canonical_category (closed by selling out, or resolved) with positive realized P&L, as a 0..1 fraction. Null when not measured. This is a trader statistic, not the pick’s probability of winning."
              },
              "n_resolved": {
                "type": ["integer", "null"],
                "description": "Number of settled markets behind win_rate; null when not measured."
              },
              "position_usd": {
                "type": "number",
                "description": "Recorded Polymarket position value on the backed outcome, in USD. It can change after this snapshot."
              },
              "opposite_position_usd": {
                "type": "number",
                "description": "Recorded position value on the other outcome of this market, in USD. Omitted when not recorded; zero is a measured value."
              },
              "stats_computed_at": {
                "type": "string",
                "format": "date-time",
                "description": "Timestamp of the recorded trader statistics."
              }
            },
            "required": [
              "address",
              "name",
              "grade",
              "canonical_category",
              "win_rate",
              "n_resolved",
              "position_usd",
              "stats_computed_at"
            ]
          },
          "traders": {
            "type": "integer",
            "description": "Public V1 S/A wallet count on the backed side, equal to sharp_wallet_count."
          },
          "backed_sharp_usd": {
            "type": "number",
            "description": "Recorded aggregate backed-side position value in USD when available, not a live balance or entry cost. The display_holders roster can include additional wallets; use the returned aggregate rather than summing that roster."
          },
          "holders": {
            "type": "array",
            "description": "Bounded S/A holder display projection from the recorded snapshot. Historical rows retain their recorded display shape.",
            "items": {
              "$ref": "#/components/schemas/PickHolder"
            }
          },
          "display_holders": {
            "type": "array",
            "description": "Optional recorded holder roster in display order, with lead_backer first when present. Preserve the returned order. The roster can include wallets outside the recorded count and aggregate fields; do not derive holder_count, wallet counts or backed_sharp_usd from its length or a sum. Position values are gross holdings on the backed outcome and can coexist with holdings on the other outcome. Historical rows retain their recorded display shape.",
            "items": {
              "$ref": "#/components/schemas/PickHolder"
            }
          },
          "holder_count": {
            "type": "integer",
            "description": "S/A holder count for the public V1 compatibility projection. display_holders can include additional grades."
          },
          "thesis": {
            "type": "string",
            "description": "Display-ready explanation of the recorded pick. Render the returned text rather than reconstructing it from holder counts or grades."
          },
          "market_url": {
            "type": "string",
            "description": "Canonical web market URL."
          },
          "polymarket_url": {
            "type": "string",
            "description": "Where this pick's outbound Polymarket link lands: Polymarket's own redirect answer for `/event/<event_slug>`, carrying the referral tag. Omitted until that redirect has been resolved; link to the event page instead when it is absent."
          },
          "event_slug": {
            "type": "string",
            "description": "The canonical /event game-page slug (one neutral page per game); omitted when the game has no neutral event page."
          },
          "event_link_slug": {
            "type": ["string", "null"],
            "description": "Backend-resolved /event destination slug for the source market. Omitted outside full responses; null is an authoritative no-link decision."
          },
          "sports_context": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PickSportsContext"
              }
            ],
            "description": "Provider-first sports context for the pick's market (team logos, league branding, live score). Full-state only; omitted when the pick is not a team-sports market."
          },
          "disclaimer": {
            "type": "string",
            "description": "Risk disclaimer shown with every pick."
          },
          "proof_pending_picks": {
            "type": "array",
            "description": "Entitled published picks whose holder proof is unreadable, ordered by rank. Unauthorized ranks appear only in locked_picks and cannot trigger proof warming. Read retry_at for the next read.",
            "items": {
              "$ref": "#/components/schemas/ProofPendingPickSlot"
            }
          },
          "entry_authorization": {
            "$ref": "#/components/schemas/PotdEntryAuthorization",
            "description": "Optional full-response entry authorization. Missing or expired authorization cannot authorize an automated entry."
          },
          "locked_picks": {
            "type": "array",
            "description": "Unauthorized unresolved published or scheduled ranks. Contains no game, provider identity, price, or identifying clock. Pro may upgrade to Max to open these ranks.",
            "items": {
              "type": "object",
              "required": ["pick_rank", "required_tier"],
              "properties": {
                "pick_rank": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 30
                },
                "required_tier": {
                  "type": "string",
                  "enum": ["max"]
                }
              }
            }
          },
          "message": {
            "type": "string",
            "description": "Actionable status, including Upgrade to Max when only locked ranks are published."
          },
          "pick_id": {
            "type": "string",
            "pattern": "^[1-9][0-9]*$",
            "description": "Stable pick row identity as decimal text. Never use a quality rank as identity."
          },
          "publication_order": {
            "type": "integer",
            "description": "Compatibility release slot. No quality claim; historic scheduling order is retained."
          },
          "is_free_selection": {
            "type": "boolean",
            "description": "Viewer-independent free selection designation. New rows store it explicitly; historic null storage uses the original free slot."
          },
          "supersedes_pick_id": {
            "deprecated": true,
            "type": ["string", "null"],
            "pattern": "^[1-9][0-9]*$",
            "description": "Deprecated (#24157): always null. No replacement lineage was ever recorded in this field; the key stays so existing V1 clients keep parsing. Identify a pick by pick_id."
          },
          "lead_backer": {
            "$ref": "#/components/schemas/PickLeadBacker",
            "description": "Optional full-only lead wallet publication facts. Omitted on legacy picks or when the recorded evidence is unavailable."
          }
        }
      },
      "PickSportsContext": {
        "type": "object",
        "required": ["league_name", "league_logo", "yes_team", "no_team", "event_matchup"],
        "description": "Provider-first sports context for a Pick of the Day market: team crests, league branding, and live score. Each team `logo` is a registered club crest or national flag as a same-origin path where one exists, and provider artwork otherwise.",
        "properties": {
          "league_name": {
            "type": ["string", "null"],
            "description": "League or competition display name (e.g. \"Premier League\")."
          },
          "competition_label": {
            "type": "string",
            "description": "Provider-owned event taxonomy from Gamma eventMetadata, joined in league · serie · tournament order with blanks and case-insensitive duplicates removed. A tennis qualifying match ends in \", Qualification\", including an ATP Challenger qualifying match, which Gamma marks only in eventMetadata.tennisFixtureSource. Separate from league_name; omitted when the provider does not supply the metadata."
          },
          "league_logo": {
            "type": ["string", "null"],
            "description": "League logo URL (provider-owned)."
          },
          "yes_team": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PickSportsTeam"
              },
              {
                "type": "null"
              }
            ],
            "description": "The team mapped to the market's YES outcome, or the parent-event home/first team when event_matchup is true."
          },
          "no_team": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PickSportsTeam"
              },
              {
                "type": "null"
              }
            ],
            "description": "The team mapped to the market's NO outcome, or the parent-event away/second team when event_matchup is true."
          },
          "game_id": {
            "type": "integer",
            "description": "Provider game identifier (Polymarket Gamma gameId); omitted when the provider supplies none."
          },
          "event_matchup": {
            "type": "boolean",
            "description": "Always present. True when the two teams are the parent-event match identity for a teamless binary leg (e.g. a draw, totals, or prop market), not the market's own outcomes."
          },
          "event_subject_team": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PickSportsTeam"
              }
            ],
            "description": "Present only alongside event_matchup: the event team the binary leg is about (provider group_item_title matched to a matchup team, e.g. Belgium for \"Will Belgium win?\"), i.e. the winner on a Yes resolution. Omitted for teamless legs (draw, totals, prop)."
          },
          "matchup_title": {
            "type": "string",
            "description": "The two teams as a single whole-game label, joined \"<home> – <away>\" (en-dash) in provider display order (e.g. \"Portugal – Uzbekistan\"). Composed server-side from the provider team names (no title/slug parsing). Present when both teams resolve a name; omitted for single-subject, teamless, or non-two-team contexts."
          }
        }
      },
      "PickSportsTeam": {
        "type": "object",
        "description": "A single sports team or competitor in a Pick of the Day market's sports context. Identity and score fields are provider-owned and nullable. The structured score fields (`sets`, `format`, `sets_won`) and the tennis fields (`headshot`, `headshot_revision`, `tour`) are backend-owned and are OMITTED rather than null when they do not apply, so a consumer must treat an absent key and a null the same way.",
        "required": [
          "label",
          "short_label",
          "full_name",
          "provider_id",
          "logo",
          "logo_mark_dark",
          "color",
          "record",
          "score",
          "logo_mark_light",
          "logo_mark_measured"
        ],
        "properties": {
          "label": {
            "type": ["string", "null"],
            "description": "Team display label as it appears on the market outcome (e.g. \"Portugal\")."
          },
          "short_label": {
            "type": ["string", "null"],
            "description": "Abbreviated team label (e.g. \"POR\")."
          },
          "full_name": {
            "type": ["string", "null"],
            "description": "The name to show for this team or competitor, the same on every surface (e.g. \"UCF Knights\", \"Oklahoma City Thunder\", \"Portugal\"). `label` keeps the market outcome's own spelling."
          },
          "provider_id": {
            "type": ["integer", "null"],
            "description": "Provider team identifier (Polymarket /teams id)."
          },
          "logo": {
            "type": ["string", "null"],
            "description": "Team crest or flag URL. Official NFL (32), WNBA (15), NBA (30), NHL (32), and MLB (30) club crests use same-origin relative paths (`/api/sports/team-logos/{league}/{abbr}.svg?v=<content hash>`); resolve relative URLs against the API origin. Vendored soccer club crests use the same path with `.png`. National teams in the registered national-team competitions use the same path with `.svg`: the official national flag, drawn whole at its own aspect. Other teams use provider artwork, including country flags for tennis players. Novelty rows, and national-team rows that are not exactly one country, retain provider artwork."
          },
          "logo_mark_dark": {
            "type": "boolean",
            "description": "True when artwork measurements show that the team mark needs a light plate on a dark background. Vendored crest verdicts are tied to the exact asset bytes; provider artwork is measured by the teams sync. Always sent; false when no current measurement marks the logo dark."
          },
          "color": {
            "type": ["string", "null"],
            "description": "Team brand color as a hex string (provider-owned)."
          },
          "record": {
            "type": ["string", "null"],
            "description": "Win-loss record as a display string (e.g. \"12-4\")."
          },
          "score": {
            "type": ["string", "null"],
            "description": "Live or final score as a display string when the game is in play or settled."
          },
          "headshot": {
            "type": "string",
            "description": "Tennis player headshot URL, served same-origin. Present only for a tennis competitor the headshot resolver matched; absent for team sports and for unmatched players, where `logo` stays the fallback."
          },
          "tour": {
            "type": "string",
            "enum": ["atp", "wta", "itf"],
            "description": "Tennis tour this competitor belongs to. Present for every tennis entry whether or not `headshot` resolved, so a consumer can tell a tennis player with no photo from a non-tennis team. Absent for every other sport. Only `atp` and `wta` name a gender; the ITF World Tennis Tour runs men's and women's events and the provider does not say which, so `itf` means tennis with gender unknown."
          },
          "sets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScoreCell"
            },
            "description": "Per-set score cells for this side, in set order. Backend-owned: render these rather than parsing `score`. Omitted entirely when the provider score is not a structured multi-set match or could not be parsed, so an absent array and an empty one carry the same meaning."
          },
          "format": {
            "$ref": "#/components/schemas/ScoreFormat"
          },
          "sets_won": {
            "type": "integer",
            "description": "Completed sets won by this side. Present only when both sides expose the same set columns, so a partially parsed scoreline reports no tally rather than a misleading one."
          },
          "headshot_revision": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Optional monotonic photo revision for this tennis player, independent of the sports score revision. Legacy stored photos start at zero. Successful new or changed image bytes advance it; source checks and attribution changes do not. Compare only for the same tour and provider_id: a higher revision replaces the portrait, an equal revision may fill a missing portrait, and a lower revision must not replace a newer one. Absent when no photo resolved."
          },
          "ranking": {
            "allOf": [
              {
                "$ref": "#/components/schemas/TennisRanking"
              }
            ],
            "description": "Optional latest retrieved ATP/WTA singles rank for this player. Absent for unranked, ambiguous, doubles, expired, or unavailable identities. This is not rank at match time."
          },
          "logo_mark_light": {
            "type": "boolean",
            "description": "True when artwork measurements show that the team mark disappears on a white background and needs a dark plate there: the light-background twin of logo_mark_dark. Vendored crest verdicts are tied to the exact asset bytes; provider artwork is measured on white by the teams sync. Always sent; false when no current measurement marks the logo light."
          },
          "logo_mark_measured": {
            "type": "boolean",
            "description": "True when logo_mark_dark and logo_mark_light are both measurements of this exact logo URL, so their false means the mark is legible on that background. Every vendored crest is measured; a provider logo is measured once the teams sync has scored it, usually within a few hourly cycles of first appearing. Always sent; false while the logo is not measured yet."
          }
        }
      },
      "ScoreCell": {
        "type": "object",
        "description": "One side's score in a single set. The verbatim provider text stays on the team's `score` string; this is the parsed form.",
        "required": ["games"],
        "properties": {
          "games": {
            "type": "integer",
            "description": "Games won in this set."
          },
          "tiebreak": {
            "type": "integer",
            "description": "Tiebreak points won in this set. Omitted when the set had no tiebreak; absence and zero are different."
          }
        }
      },
      "ScoreFormat": {
        "type": "string",
        "enum": ["two_side", "multi_set", "esports_series"],
        "description": "Shape the provider score string was parsed into. `two_side` is one aggregate per side (basketball `105-98`), `multi_set` is per-set columns (tennis `6-7(5-7), 6-0, 1-0`), `esports_series` is a maps/sets/format triplet (`000-000|2-0|Bo3`). Omitted when the score could not be parsed."
      },
      "PickOfTheDayArchive": {
        "type": "object",
        "required": ["picks", "days", "hit_rate"],
        "properties": {
          "picks": {
            "type": "array",
            "description": "Published Pick of the Day selections that have not been withdrawn, newest first by pick_date and then pick_rank within each product day. Withdrawn rows stay excluded after settlement.",
            "items": {
              "$ref": "#/components/schemas/PickOfTheDayArchiveEntry"
            }
          },
          "days": {
            "type": "array",
            "description": "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.",
            "items": {
              "$ref": "#/components/schemas/PickOfTheDayArchiveDay"
            }
          },
          "hit_rate": {
            "$ref": "#/components/schemas/PickOfTheDayHitRate"
          },
          "page": {
            "type": "object",
            "required": ["limit", "returned", "total", "has_more", "next_cursor"],
            "properties": {
              "has_more": {
                "type": "boolean"
              },
              "limit": {
                "type": "integer"
              },
              "next_cursor": {
                "type": ["string", "null"]
              },
              "returned": {
                "type": "integer"
              },
              "total": {
                "type": "integer"
              }
            }
          }
        }
      },
      "PickOfTheDayArchiveSummary": {
        "description": "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.",
        "type": "object",
        "properties": {
          "hit_rate": {
            "type": "object",
            "required": [
              "wins",
              "losses",
              "decided",
              "pct",
              "void",
              "pending",
              "stake_usd",
              "net_profit_usd",
              "staked_usd",
              "roi_pct",
              "net_profit_display",
              "roi_display",
              "win_rate_display",
              "clv_eligible",
              "clv_total",
              "clv_measured",
              "clv_applicable",
              "clv_not_applicable",
              "clv_pending",
              "clv_unavailable",
              "clv_state",
              "clv_beats_close",
              "clv_ties"
            ],
            "properties": {
              "clv_applicable": {
                "type": "integer"
              },
              "clv_avg_display": {
                "type": "string"
              },
              "clv_avg_pct": {
                "type": "number"
              },
              "clv_avg_pp": {
                "type": "number"
              },
              "clv_avg_pp_display": {
                "type": "string"
              },
              "clv_beats_close": {
                "type": "integer"
              },
              "clv_coverage_display": {
                "type": "string"
              },
              "clv_coverage_explanation": {
                "type": "string"
              },
              "clv_coverage_pct": {
                "type": "number"
              },
              "clv_eligible": {
                "type": "integer"
              },
              "clv_measured": {
                "type": "integer"
              },
              "clv_not_applicable": {
                "type": "integer"
              },
              "clv_pending": {
                "type": "integer"
              },
              "clv_state": {
                "type": "string"
              },
              "clv_ties": {
                "type": "integer"
              },
              "clv_total": {
                "type": "integer"
              },
              "clv_unavailable": {
                "type": "integer"
              },
              "decided": {
                "type": "integer"
              },
              "losses": {
                "type": "integer"
              },
              "net_profit_display": {
                "type": "string"
              },
              "net_profit_usd": {
                "type": "number"
              },
              "pct": {
                "type": "number"
              },
              "pending": {
                "type": "integer"
              },
              "roi_display": {
                "type": "string"
              },
              "roi_pct": {
                "type": "number"
              },
              "stake_usd": {
                "type": "number"
              },
              "staked_usd": {
                "type": "number"
              },
              "unit_score": {
                "type": "number"
              },
              "unit_score_display": {
                "type": "string"
              },
              "void": {
                "type": "integer"
              },
              "win_rate_display": {
                "type": "string"
              },
              "wins": {
                "type": "integer"
              }
            }
          },
          "page": {
            "type": "object",
            "required": ["limit", "returned", "total", "has_more", "next_cursor"],
            "properties": {
              "has_more": {
                "type": "boolean"
              },
              "limit": {
                "type": "integer"
              },
              "next_cursor": {
                "type": ["string", "null"]
              },
              "returned": {
                "type": "integer"
              },
              "total": {
                "type": "integer"
              }
            }
          },
          "picks": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "pick_id",
                "pick_date",
                "publication_order",
                "is_free_selection",
                "outcome"
              ],
              "properties": {
                "backed_price": {
                  "type": "number"
                },
                "backed_side_locked": {
                  "type": "boolean"
                },
                "clv_pct": {
                  "type": "number"
                },
                "display_category": {
                  "type": "string"
                },
                "is_free_selection": {
                  "type": "boolean"
                },
                "matchup": {
                  "type": "string"
                },
                "outcome": {
                  "type": "string"
                },
                "pick_date": {
                  "type": "string",
                  "format": "date"
                },
                "pick_id": {
                  "type": "string"
                },
                "pick_outcome_label": {
                  "type": "string"
                },
                "publication_order": {
                  "type": "integer"
                },
                "required_tier": {
                  "type": "string"
                },
                "top_grade": {
                  "type": "string"
                },
                "unit_score": {
                  "type": "number"
                }
              }
            }
          },
          "view": {
            "type": "string"
          }
        },
        "required": ["view", "hit_rate", "picks", "page"]
      },
      "PickOfTheDayArchiveDay": {
        "type": "object",
        "required": ["date", "picks", "wins", "losses", "void", "pending"],
        "properties": {
          "date": {
            "type": "string",
            "format": "date",
            "description": "The product day (YYYY-MM-DD)."
          },
          "picks": {
            "type": "integer",
            "minimum": 1,
            "description": "Published picks on the day: wins + losses + void + pending."
          },
          "wins": {
            "type": "integer",
            "minimum": 0,
            "description": "Picks on the day that resolved as a win, counted by the same pass as hit_rate.wins, so the day entries sum to the headline record."
          },
          "losses": {
            "type": "integer",
            "minimum": 0,
            "description": "Picks on the day that resolved as a loss, counted by the same pass as hit_rate.losses."
          },
          "void": {
            "type": "integer",
            "minimum": 0,
            "description": "Picks on the day that resolved void: the market settled with no winner, or the game was suspended or postponed and not completed within 72 hours of kickoff. A void is neither a win nor a loss and is not staked, so it enters no money figure."
          },
          "pending": {
            "type": "integer",
            "minimum": 0,
            "description": "Picks on the day not yet resolved. A day whose picks are all pending is a real 0-0 day with pending > 0, not a missing record."
          },
          "unit_score": {
            "type": "number",
            "format": "double",
            "description": "Net units over the day's visible, valued, staked (win or loss) picks: the same population staked_usd runs over. Omitted when the day has not scored -- every pick still pending or void, or a price-gated current row -- which is not the same as a real 0.0 day."
          },
          "unit_score_display": {
            "type": "string",
            "description": "unit_score pre-formatted as signed units to two decimals (for example +1.24u or -2.00u), by the same formatter the per-pick unit_score_display and hit_rate.unit_score_display use. Present exactly when unit_score is; unit_score is the source value."
          },
          "sweep": {
            "type": "string",
            "enum": ["win", "loss"],
            "description": "win when every decided pick on the day won, loss when every one lost, over at least three decided (win or loss) picks with nothing pending. Omitted for every other day. A void is not a result: it neither lifts a day over the floor nor spoils a sweep."
          }
        }
      },
      "PickOfTheDayArchiveEntry": {
        "type": "object",
        "required": [
          "pick_date",
          "pick_rank",
          "outcome",
          "pick_id",
          "publication_order",
          "is_free_selection",
          "supersedes_pick_id"
        ],
        "properties": {
          "pick_date": {
            "type": "string",
            "format": "date",
            "description": "The pick's local publication date (YYYY-MM-DD)."
          },
          "pick_rank": {
            "type": "integer",
            "minimum": 1,
            "maximum": 30,
            "description": "Deprecated compatibility daily release slot; use pick_id for identity and publication_order for scheduling.",
            "deprecated": true
          },
          "published_at": {
            "type": "string",
            "format": "date-time",
            "description": "When this selection was published, as RFC3339 UTC. Use this instant for publication feeds and timelines; pick_date is the America/New_York product day, not a publication timestamp. Absent only for historical rows whose publication instant is unknown."
          },
          "matchup": {
            "type": "string",
            "description": "Human-readable matchup (e.g. \"Portugal vs. Uzbekistan\")."
          },
          "category": {
            "type": "string",
            "description": "Frozen canonical sport bucket (e.g. \"Basketball\", \"MMA\", or \"Soccer\"). Existing semantics are unchanged; presentation consumers should prefer display_category when present."
          },
          "display_category": {
            "type": "string",
            "description": "Frozen public presentation category. Tennis uses the provider-verified ATP or WTA tour, including Wimbledon and doubles; unknown tours retain Tennis. Every men's and women's cricket competition uses Cricket. Other sports use the curated league, esports title or soccer competition label, then the provider series name without its season year, then category when no competition is known. The canonical category and measured cohort are unchanged: an esports title still uses the pooled Esports category. Optional for mixed-version client compatibility."
          },
          "image_url": {
            "type": "string",
            "description": "Provider (Polymarket Gamma) market thumbnail URL (markets.image); omitted (not null) when the market has no image. Public regardless of the backed-side gate, so present for pending rows too."
          },
          "pick_outcome_label": {
            "type": "string",
            "description": "The backed side's outcome label. Omitted for a still-pending pick when the request is not from an authenticated Pro key."
          },
          "top_grade": {
            "type": "string",
            "description": "Recorded top grade on the backed side in the public V1 compatibility projection. Omitted when unavailable. Historical values remain recorded snapshots."
          },
          "outcome": {
            "type": "string",
            "enum": ["pending", "win", "loss", "void"],
            "description": "Settlement outcome of the backed side; 'pending' until the market resolves."
          },
          "outcome_display": {
            "type": "string",
            "description": "Pre-formatted settlement status for display: \"Win\" / \"Loss\" / \"Void\" / \"Pending\" -- the outcome enum above as a label, from the same formatter the pick payload's outcome_display uses. Convenience only; outcome is the source value."
          },
          "resolved_at": {
            "type": "string",
            "format": "date-time",
            "description": "When outcome was LAST written to a settled value (RFC3339 UTC), the same instant the commitment ledger publishes. It moves with a corrected market re-mapping an already-settled pick. Omitted (not null) for a pending pick and for a pick that settled before the instant was recorded, so absence means the instant is unknown, never that the pick is unsettled -- outcome answers that. Additive and optional for mixed-version client compatibility."
          },
          "stake_usd": {
            "type": "number",
            "description": "The flat stake this row was valued at, in USD: 1000 since 2026-09-22 (100 before). Every row of the record is valued at the current stake, including picks published before the change. Present exactly when return_usd is."
          },
          "return_usd": {
            "type": "number",
            "description": "Gross return of stake_usd on this resolved pick: a win returns stake_usd / backed_price and a loss returns 0. A loss always returns 0 (the whole stake is lost regardless of price). The operand is published beside it as backed_price on every row that carries a return, so the entry never has to be recovered by inverting this number. Omitted (not null) for a still-pending pick, for a void (the market settled with no winner, or the game was suspended or postponed and not completed within 72 hours of kickoff, so the pick is not staked) and for a resolved WIN with no frozen price (a win's payout needs the price); mirrors the backend skip-when-absent behavior and the route-client optional (non-nullable) schema."
          },
          "return_per_100": {
            "type": "number",
            "description": "The same return on a literal $100 (a win returns 100 / backed_price, a loss 0), kept for compatibility: the field predates stake_usd and its name promises the $100 basis. Present exactly when return_usd is."
          },
          "payout_display": {
            "type": "string",
            "description": "Pre-formatted return_usd as USD with cents: \"$2,000.00\". Present exactly when return_usd is -- it is formatted from that already-gated value -- so it is omitted for a still-pending pick, a void, an unpriced win, and any pick whose backed side is withheld. Convenience only; return_usd is the source value."
          },
          "backed_price": {
            "type": "number",
            "description": "Frozen price of the backed side (0..1) that return_usd and return_per_100 were computed from: on a win, stake_usd / backed_price equals return_usd. It is the Polymarket CLOB order book midpoint at release, frozen write-once at publication, not an executed fill: a buyer lifts the ask, so a subscriber's own entry is usually a little worse than this price. Present exactly when return_usd is, and on a void, which carries no return: so it is omitted for a still-pending pick, an unpriced win, and any pick whose backed side is withheld."
          },
          "clv_pct": {
            "type": "number",
            "description": "Closing-line value toward the backed side, computed as (close / entry - 1) * 100. Omitted when the row is gated, ineligible, or not measured."
          },
          "clv_display": {
            "type": "string",
            "description": "Backend-formatted signed CLV percentage, present exactly when clv_pct is present."
          },
          "clv_entry_price": {
            "type": "number",
            "description": "Entry operand of clv_pct: the frozen pick probability the close is compared against. It equals backed_price, which CLV eligibility requires. Present exactly when clv_pct is."
          },
          "clv_close_price": {
            "type": "number",
            "description": "Close operand of clv_pct: the last valid Polymarket probability before the close bound (kickoff, or the first instant the live feed reported the game in progress when that came earlier). Present exactly when clv_pct is; the close timestamp stays private."
          },
          "clv_applicability": {
            "type": "string",
            "enum": ["applicable", "not_applicable"],
            "description": "Whether CLV applies. A visible resolved pick published after kickoff is not_applicable."
          },
          "clv_explanation": {
            "type": "string",
            "description": "Backend-owned CLV text. A measured row names the entry, then the close, then the formula (close / entry - 1) x 100 and its rounded result; otherwise it gives the reason CLV does not apply or is unavailable."
          },
          "clv_status": {
            "type": "string",
            "description": "Exact backend CLV capture disposition for this visible row. Pending and terminal provider or quality statuses are distinguishable; capture timestamps are never serialized, while a measured row's entry and close prices are published as clv_entry_price and clv_close_price."
          },
          "clv_basis": {
            "type": "string",
            "description": "Backend-owned CLV evidence basis. Source-null price-match bases preserve unknown original provenance. `historical_provider_nearby_price_match` requires a matching Polymarket point within five minutes before publication."
          },
          "unit_score": {
            "type": "number",
            "description": "Net return for this pick in stake units (return_usd / stake_usd - 1), where one unit is one stake_usd stake; the same figure under any stake size. Omitted when the backed side is withheld or the pick is not valued."
          },
          "unit_score_display": {
            "type": "string",
            "description": "Backend-formatted signed unit score, present exactly when unit_score is present."
          },
          "required_tier": {
            "type": "string",
            "enum": ["account", "insider", "max"],
            "description": "The account or paid tier needed to open this unresolved rank."
          },
          "backed_side_locked": {
            "type": "boolean",
            "description": "True for an unauthorized unresolved row. Game identity, category, image, publication clock and all backed facts are omitted."
          },
          "pick_id": {
            "type": "string",
            "pattern": "^[1-9][0-9]*$",
            "description": "Stable pick row identity as decimal text. Never use a quality rank as identity."
          },
          "publication_order": {
            "type": "integer",
            "description": "Compatibility release slot. No quality claim; historic scheduling order is retained."
          },
          "is_free_selection": {
            "type": "boolean",
            "description": "Viewer-independent free selection designation. New rows store it explicitly; historic null storage uses the original free slot."
          },
          "supersedes_pick_id": {
            "deprecated": true,
            "type": ["string", "null"],
            "pattern": "^[1-9][0-9]*$",
            "description": "Deprecated (#24157): always null. No replacement lineage was ever recorded in this field; the key stays so existing V1 clients keep parsing. Identify a pick by pick_id."
          }
        }
      },
      "PickOfTheDayHitRate": {
        "type": "object",
        "required": [
          "wins",
          "losses",
          "decided",
          "pct",
          "void",
          "pending",
          "stake_usd",
          "net_profit_usd",
          "staked_usd",
          "roi_pct",
          "net_profit_display",
          "roi_display",
          "win_rate_display",
          "clv_pending",
          "clv_unavailable",
          "clv_state",
          "clv_eligible",
          "clv_total",
          "clv_measured",
          "clv_applicable",
          "clv_not_applicable",
          "clv_beats_close",
          "clv_ties",
          "series"
        ],
        "properties": {
          "wins": {
            "type": "integer",
            "description": "Number of decided picks that won."
          },
          "losses": {
            "type": "integer",
            "description": "Number of decided picks that lost."
          },
          "decided": {
            "type": "integer",
            "description": "Number of decided picks (wins + losses); excludes void and pending."
          },
          "pct": {
            "type": "number",
            "description": "Rolling hit rate as a percentage (wins / decided * 100, to 1 decimal); 0 when none are decided."
          },
          "void": {
            "type": "integer",
            "description": "Number of picks that resolved void (excluded from the hit rate)."
          },
          "pending": {
            "type": "integer",
            "description": "Number of picks still pending resolution (excluded from the hit rate)."
          },
          "stake_usd": {
            "type": "number",
            "description": "The flat stake every money figure here assumes, in USD: 1000 since 2026-09-22 (100 before). Always present."
          },
          "net_profit_usd": {
            "type": "number",
            "description": "Cumulative profit (USD) of a stake_usd-per-pick strategy over visible valued settled picks: a priced win pays stake_usd/backed_price - stake_usd, every visible loss pays -stake_usd independent of price. A void is not staked and adds nothing. An unpriced visible win and a current non-Insider row whose price is gated remain in wins/losses but are excluded from price-derived totals."
          },
          "staked_usd": {
            "type": "number",
            "description": "Total staked (USD) = stake_usd * count of visible valued settled picks: every visible loss and every priced win. Voids, unpriced wins and current non-Insider rows whose price is gated are excluded."
          },
          "roi_pct": {
            "type": "number",
            "description": "Return on the staked amount as a percentage (net_profit_usd / staked_usd * 100, to 1 decimal); 0 when nothing is staked."
          },
          "net_profit_display": {
            "type": "string",
            "description": "Pre-formatted net profit for display, e.g. \"+$100\" / \"-$40\". Whole dollars, signed, round-then-signed so a rounds-to-zero record reads \"+$0\" (never \"-$0\"). Convenience only; net_profit_usd is the source value."
          },
          "roi_display": {
            "type": "string",
            "description": "Pre-formatted ROI for display, e.g. \"+8.3%\" / \"-20.0%\". One decimal, signed, round-then-signed so a rounds-to-zero record reads \"+0.0%\" (never \"-0.0%\"). Convenience only; roi_pct is the source value."
          },
          "win_rate_display": {
            "type": "string",
            "description": "Pre-formatted win rate for display, e.g. \"92.3%\". One decimal, unsigned. Convenience only; pct is the source value."
          },
          "unit_score": {
            "type": "number",
            "description": "Cumulative net return in stake units over the same valued win/loss population as net_profit_usd."
          },
          "unit_score_display": {
            "type": "string",
            "description": "Backend-formatted signed cumulative unit score, for example \"+1.25u\". Omitted when no valued settled pick contributes to the aggregate."
          },
          "clv_pending": {
            "type": "integer",
            "description": "Visible resolved archive rows with no CLV capture disposition yet."
          },
          "clv_unavailable": {
            "type": "integer",
            "description": "Visible resolved archive rows with a terminal non-measured CLV disposition."
          },
          "clv_state": {
            "type": "string",
            "enum": ["measured", "pending", "unavailable", "not_applicable", "none"],
            "description": "Aggregate CLV state. Counts remain available for mixed measured/pending/unavailable populations."
          },
          "clv_eligible": {
            "type": "integer",
            "description": "Visible resolved archive rows with valid basis-specific CLV entry evidence. Known-source bases require CLOB provenance; historical_provider_price_match instead requires source provenance to remain null and the latest provider p entry in the one-hour window at or before publication to match the stored display."
          },
          "clv_total": {
            "type": "integer",
            "description": "Every visible resolved archive row, including post-kickoff picks. A price-gated current row is excluded until its backed side becomes visible."
          },
          "clv_measured": {
            "type": "integer",
            "description": "Eligible resolved public rows with a measured Polymarket CLOB close."
          },
          "clv_applicable": {
            "type": "integer",
            "description": "Visible resolved rows published before kickoff. This is the CLV coverage denominator."
          },
          "clv_not_applicable": {
            "type": "integer",
            "description": "Visible resolved rows published after kickoff. These rows remain public but do not enter coverage."
          },
          "clv_coverage_pct": {
            "type": "number",
            "description": "Measured divided by clv_applicable as a percentage. Omitted when clv_applicable is zero."
          },
          "clv_coverage_display": {
            "type": "string",
            "description": "Backend-formatted measured/clv_applicable coverage percentage."
          },
          "clv_coverage_explanation": {
            "type": "string",
            "description": "Backend-owned coverage count text, including the excluded post-kickoff count."
          },
          "clv_avg_pct": {
            "type": "number",
            "description": "Arithmetic mean of per-pick ratio CLV, (close / entry - 1) * 100. A cheap entry weighs more here than a favorite, so the headline average is clv_avg_pp; this field is kept for continuity. Suppressed until at least five measured rows exist."
          },
          "clv_avg_display": {
            "type": "string",
            "description": "Backend-formatted signed average CLV percentage, present when clv_avg_pct is present."
          },
          "clv_avg_pp": {
            "type": "number",
            "description": "Arithmetic mean of the measured closing-line move in percentage points, (close - entry) * 100, so every pick counts on the same scale. The headline CLV average. Covers the same measured rows as clv_avg_pct and is suppressed under the same five-row floor."
          },
          "clv_avg_pp_display": {
            "type": "string",
            "description": "Backend-formatted signed average in percentage points, for example \"+0.4 pp\"; a value that rounds to zero reads \"0.0 pp\". Present when clv_avg_pp is present."
          },
          "clv_beats_close": {
            "type": "integer",
            "description": "Measured public rows where close is strictly greater than entry."
          },
          "clv_ties": {
            "type": "integer",
            "description": "Measured public rows where close exactly equals entry."
          },
          "series": {
            "type": "array",
            "description": "Cumulative track-record series, one point per decided (win/loss) pick in ascending pick_date order (pending and void picks add no point). A non-valued decided row carries cumulative profit forward while advancing hit rate. The last point's net_profit_usd and hit_rate_pct equal the headline net_profit_usd and pct by construction. Empty when nothing is decided.",
            "items": {
              "type": "object",
              "required": ["date", "net_profit_usd", "hit_rate_pct"],
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date",
                  "description": "The decided pick's publish date (YYYY-MM-DD)."
                },
                "net_profit_usd": {
                  "type": "number",
                  "description": "Running cumulative stake_usd-per-pick profit (USD) through this pick; valued losses and priced wins are booked, while a non-valued decided row carries profit forward unchanged."
                },
                "hit_rate_pct": {
                  "type": "number",
                  "description": "Running rolling hit rate (wins / decided * 100, to 1 decimal) through this pick."
                }
              }
            }
          }
        }
      },
      "PickOfTheDayLedger": {
        "type": "object",
        "description": "The commitment ledger: every published pick, ascending, in the state its commitment is actually in. The counts are derived from entries in the same pass that builds it.",
        "required": ["entries", "entry_count", "sealed_count", "opened_count", "uncommitted_count"],
        "properties": {
          "entries": {
            "type": "array",
            "description": "One entry per published (pick_date, pick_rank), ascending by pick_date then pick_rank.",
            "items": {
              "$ref": "#/components/schemas/PickOfTheDayLedgerEntry"
            }
          },
          "entry_count": {
            "type": "integer",
            "description": "Number of entries, all states included."
          },
          "sealed_count": {
            "type": "integer",
            "description": "Entries committed to and not yet settled."
          },
          "opened_count": {
            "type": "integer",
            "description": "Entries committed to and verifiable now."
          },
          "uncommitted_count": {
            "type": "integer",
            "description": "Entries carrying no commitment, so provable by nothing: the honest size of the unprovable part of the record. It only stops growing; no pick is ever retro-sealed."
          }
        }
      },
      "PickOfTheDayLedgerEntry": {
        "description": "One ledger entry. Read `state` to know which shape you have; the three are disjoint.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/PickOfTheDayLedgerSealedEntry"
          },
          {
            "$ref": "#/components/schemas/PickOfTheDayLedgerOpenedEntry"
          },
          {
            "$ref": "#/components/schemas/PickOfTheDayLedgerUncommittedEntry"
          }
        ],
        "discriminator": {
          "propertyName": "state",
          "mapping": {
            "sealed": "#/components/schemas/PickOfTheDayLedgerSealedEntry",
            "opened": "#/components/schemas/PickOfTheDayLedgerOpenedEntry",
            "uncommitted": "#/components/schemas/PickOfTheDayLedgerUncommittedEntry"
          }
        }
      },
      "PickOfTheDayLedgerSealedEntry": {
        "type": "object",
        "description": "An unresolved published pick. Carries only date, rank, hash, algorithm, seal instant and permalink. Kickoff and game identity are withheld; seal time remains public commitment provenance.",
        "required": [
          "state",
          "pick_date",
          "pick_rank",
          "commitment_hash",
          "commitment_algo",
          "sealed_at",
          "permalink",
          "pick_id",
          "publication_order",
          "is_free_selection",
          "supersedes_pick_id",
          "commitment_version"
        ],
        "properties": {
          "state": {
            "type": "string",
            "const": "sealed"
          },
          "pick_date": {
            "type": "string",
            "format": "date",
            "description": "ET product day the pick belongs to (YYYY-MM-DD)."
          },
          "pick_rank": {
            "type": "integer",
            "description": "Deprecated compatibility daily release slot; use pick_id for identity and publication_order for scheduling.",
            "deprecated": true
          },
          "commitment_hash": {
            "type": "string",
            "description": "sha256(canonical_json(payload) || nonce), lowercase hex, no 0x prefix. Publishable the moment the pick releases: without the nonce it is not invertible."
          },
          "commitment_algo": {
            "type": "string",
            "const": "sha256(canonical_json(payload)||nonce)",
            "description": "The construction the hash was taken with, stated in the response so a verifier never has to guess the serialization."
          },
          "sealed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the hash was frozen. Always strictly before kickoff: a pick that reaches kickoff unsealed stays unsealed forever, because a seal written after the game started would be a backdated proof."
          },
          "permalink": {
            "type": "string",
            "format": "uri",
            "description": "The pick's stable public page, `https://0xinsider.com/pick-of-the-day/picks/{pick_id}`."
          },
          "pick_id": {
            "type": "string",
            "pattern": "^[1-9][0-9]*$",
            "description": "Stable pick row identity as decimal text. Never use a quality rank as identity."
          },
          "publication_order": {
            "type": "integer",
            "description": "Compatibility release slot. No quality claim; historic scheduling order is retained."
          },
          "is_free_selection": {
            "type": "boolean",
            "description": "Viewer-independent free selection designation. New rows store it explicitly; historic null storage uses the original free slot."
          },
          "supersedes_pick_id": {
            "deprecated": true,
            "type": ["string", "null"],
            "pattern": "^[1-9][0-9]*$",
            "description": "Deprecated (#24157): always null. No replacement lineage was ever recorded in this field; the key stays so existing V1 clients keep parsing. Identify a pick by pick_id."
          },
          "commitment_version": {
            "type": "integer",
            "enum": [1, 2],
            "description": "Explicit proof provenance: 1 retains historic eight-field canonical JSON; 2 binds stable pick_id and version without pick_rank."
          }
        }
      },
      "PickOfTheDayLedgerOpenedEntry": {
        "type": "object",
        "description": "A settled pick whose commitment is open: the nonce plus the exact payload the hash was taken over. Concatenate the payload bytes as received with the decoded nonce and sha256 them to reproduce commitment_hash.",
        "required": [
          "state",
          "pick_date",
          "pick_rank",
          "commitment_hash",
          "commitment_nonce",
          "commitment_algo",
          "sealed_at",
          "resolved_at",
          "kickoff",
          "payload",
          "outcome",
          "withdrawal_reason",
          "matchup",
          "category",
          "permalink",
          "pick_id",
          "publication_order",
          "is_free_selection",
          "supersedes_pick_id",
          "commitment_version"
        ],
        "properties": {
          "state": {
            "type": "string",
            "const": "opened"
          },
          "pick_date": {
            "type": "string",
            "format": "date",
            "description": "ET product day the pick belongs to (YYYY-MM-DD)."
          },
          "pick_rank": {
            "type": "integer",
            "description": "Deprecated compatibility daily release slot; use pick_id for identity and publication_order for scheduling.",
            "deprecated": true
          },
          "commitment_hash": {
            "type": "string",
            "description": "sha256(canonical_json(payload) || nonce), lowercase hex, no 0x prefix. Publishable the moment the pick releases: without the nonce it is not invertible."
          },
          "commitment_nonce": {
            "type": "string",
            "description": "The 32-byte nonce the hash was taken over, lowercase hex, no 0x prefix. Secret while the pick is live: a pick payload is low entropy, so a published nonce on a live pick would hand out the backed side."
          },
          "commitment_algo": {
            "type": "string",
            "const": "sha256(canonical_json(payload)||nonce)",
            "description": "The construction the hash was taken with, stated in the response so a verifier never has to guess the serialization."
          },
          "sealed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the hash was frozen. Always strictly before kickoff: a pick that reaches kickoff unsealed stays unsealed forever, because a seal written after the game started would be a backdated proof."
          },
          "resolved_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When outcome was LAST written to a settled value, or null when that instant is unknown. It moves with a corrected market re-mapping an already-settled pick, while commitment_hash stays untouched -- which is how a mirror that keeps history sees a correction."
          },
          "kickoff": {
            "type": "string",
            "format": "date-time",
            "description": "The frozen provider kickoff in the canonical payload form: whole seconds, UTC, literal Z. This exact string reappears inside payload.kickoff when the pick opens."
          },
          "payload": {
            "$ref": "#/components/schemas/PickOfTheDayCommitmentPayload"
          },
          "outcome": {
            "type": "string",
            "enum": ["win", "loss", "void"],
            "description": "How the pick settled. Never pending: a pending pick is a sealed entry."
          },
          "withdrawal_reason": {
            "type": ["string", "null"],
            "enum": ["provider_game_cancelled", "published_after_kickoff", null],
            "description": "Why the site withdrew this pick from its track record, or null when the pick counts. provider_game_cancelled: Polymarket marked the game Cancelled while the pick was pending. published_after_kickoff: the pick was published at or after its game started, including a suspended match that resumed later, so it was never a pre-game pick; this can be set after the pick settled. A withdrawn pick keeps its commitment and its real outcome here, but the site's record leaves it out of every count and money figure. Not part of the hashed payload, so it never moves commitment_hash."
          },
          "matchup": {
            "type": "string",
            "description": "Frozen matchup, for a reader."
          },
          "category": {
            "type": "string",
            "description": "Frozen canonical sport bucket (for example Basketball or MMA), not the exact public league identity; the archive owns that."
          },
          "permalink": {
            "type": "string",
            "format": "uri",
            "description": "The pick's stable public page, `https://0xinsider.com/pick-of-the-day/picks/{pick_id}`."
          },
          "pick_id": {
            "type": "string",
            "pattern": "^[1-9][0-9]*$",
            "description": "Stable pick row identity as decimal text. Never use a quality rank as identity."
          },
          "publication_order": {
            "type": "integer",
            "description": "Compatibility release slot. No quality claim; historic scheduling order is retained."
          },
          "is_free_selection": {
            "type": "boolean",
            "description": "Viewer-independent free selection designation. New rows store it explicitly; historic null storage uses the original free slot."
          },
          "supersedes_pick_id": {
            "deprecated": true,
            "type": ["string", "null"],
            "pattern": "^[1-9][0-9]*$",
            "description": "Deprecated (#24157): always null. No replacement lineage was ever recorded in this field; the key stays so existing V1 clients keep parsing. Identify a pick by pick_id."
          },
          "commitment_version": {
            "type": "integer",
            "enum": [1, 2],
            "description": "Explicit proof provenance: 1 retains historic eight-field canonical JSON; 2 binds stable pick_id and version without pick_rank."
          }
        }
      },
      "PickOfTheDayLedgerUncommittedEntry": {
        "type": "object",
        "description": "A pick without a commitment, retained so the record cannot omit unprovable entries. Unresolved entries omit game identity; once resolved, matchup, category and payload become public. Existing opened canonical payload bytes and hashes are unchanged.",
        "required": [
          "state",
          "pick_date",
          "pick_rank",
          "pre_commitment",
          "outcome",
          "resolved_at",
          "payload",
          "permalink",
          "pick_id",
          "publication_order",
          "is_free_selection",
          "supersedes_pick_id"
        ],
        "properties": {
          "state": {
            "type": "string",
            "const": "uncommitted"
          },
          "pick_date": {
            "type": "string",
            "format": "date",
            "description": "ET product day the pick belongs to (YYYY-MM-DD)."
          },
          "pick_rank": {
            "type": "integer",
            "description": "Deprecated compatibility daily release slot; use pick_id for identity and publication_order for scheduling.",
            "deprecated": true
          },
          "pre_commitment": {
            "type": "boolean",
            "const": true,
            "description": "Always true: this pick has no commitment and never will."
          },
          "outcome": {
            "type": "string",
            "enum": ["pending", "win", "loss", "void"],
            "description": "How the pick settled, or pending."
          },
          "withdrawal_reason": {
            "type": ["string", "null"],
            "enum": ["provider_game_cancelled", "published_after_kickoff", null],
            "description": "Omitted while the pick is pending; once it settles, why the site withdrew it from its track record, or null when the pick counts. provider_game_cancelled: Polymarket marked the game Cancelled while the pick was pending. published_after_kickoff: the pick was published at or after its game started, including a suspended match that resumed later, so it was never a pre-game pick; this can be set after the pick settled. A withdrawn pick stays here with its real outcome, but the site's record leaves it out of every count and money figure."
          },
          "matchup": {
            "type": "string",
            "description": "Frozen matchup, for a reader."
          },
          "category": {
            "type": "string",
            "description": "Frozen canonical sport bucket (for example Basketball or MMA), not the exact public league identity; the archive owns that."
          },
          "resolved_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When outcome was LAST written to a settled value, or null when that instant is unknown. It moves with a corrected market re-mapping an already-settled pick, while commitment_hash stays untouched -- which is how a mirror that keeps history sees a correction."
          },
          "payload": {
            "description": "The pick's market, side and price once it has settled; null while it is pending, and null for a settled pick whose stored row lacks one of these columns. Not hashed: nothing was committed over these values, which is what pre_commitment: true says.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/PickOfTheDayUncommittedPayload"
              },
              {
                "type": "null"
              }
            ]
          },
          "permalink": {
            "type": "string",
            "format": "uri",
            "description": "The pick's stable public page, `https://0xinsider.com/pick-of-the-day/picks/{pick_id}`."
          },
          "pick_id": {
            "type": "string",
            "pattern": "^[1-9][0-9]*$",
            "description": "Stable pick row identity as decimal text. Never use a quality rank as identity."
          },
          "publication_order": {
            "type": "integer",
            "description": "Compatibility release slot. No quality claim; historic scheduling order is retained."
          },
          "is_free_selection": {
            "type": "boolean",
            "description": "Viewer-independent free selection designation. New rows store it explicitly; historic null storage uses the original free slot."
          },
          "supersedes_pick_id": {
            "deprecated": true,
            "type": ["string", "null"],
            "pattern": "^[1-9][0-9]*$",
            "description": "Deprecated (#24157): always null. No replacement lineage was ever recorded in this field; the key stays so existing V1 clients keep parsing. Identify a pick by pick_id."
          }
        }
      },
      "PickOfTheDayCommitmentPayload": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/PickOfTheDayCommitmentPayloadV1"
          },
          {
            "$ref": "#/components/schemas/PickOfTheDayCommitmentPayloadV2"
          }
        ],
        "description": "Select using the entry commitment_version, never implicit payload shape. All historic v1 hashes remain unchanged."
      },
      "PickOfTheDayUncommittedPayload": {
        "type": "object",
        "description": "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.",
        "required": [
          "backed_price",
          "condition_id",
          "kickoff",
          "pick_date",
          "pick_outcome_index",
          "pick_outcome_label",
          "pick_rank",
          "platform"
        ],
        "properties": {
          "backed_price": {
            "type": "string",
            "description": "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."
          },
          "condition_id": {
            "type": "string",
            "description": "Provider condition id of the backed market."
          },
          "kickoff": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Frozen provider kickoff, UTC, literal Z; null when no kickoff was frozen. Whole seconds render exactly as the commitment payload does; a sub-second instant keeps its fraction rather than being truncated, since nothing here is hashed."
          },
          "pick_date": {
            "type": "string",
            "format": "date",
            "description": "ET product day (YYYY-MM-DD)."
          },
          "pick_outcome_index": {
            "type": "integer",
            "enum": [0, 1],
            "description": "Index of the backed outcome within the market."
          },
          "pick_outcome_label": {
            "type": "string",
            "description": "Frozen display label of the backed outcome."
          },
          "pick_rank": {
            "type": "integer",
            "description": "1-based daily slot."
          },
          "platform": {
            "type": "string",
            "enum": ["polymarket"],
            "description": "Provider platform. Always polymarket."
          }
        }
      },
      "LeaderboardEntry": {
        "type": "object",
        "required": ["id", "address", "platform"],
        "properties": {
          "id": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "username": {
            "type": "string"
          },
          "grade": {
            "type": "string",
            "enum": ["S", "A", "B", "C", "D", "F"]
          },
          "streak_tier": {
            "type": "string",
            "enum": ["hot", "rising", "neutral", "cooling", "cold"],
            "description": "Hot-streak tier (trailing-7d cross-sectional percentile); a separate axis from the all-time grade. Omitted when there is no recent activity."
          },
          "score": {
            "type": "number"
          },
          "pnl": {
            "type": "number",
            "deprecated": true,
            "x-never-sent": true,
            "description": "Deprecated since 2026-10-27 and never sent. It was Polymarket's all-time leaderboard P&L, which covered every Polymarket market of the wallet, and wallet figures cover sports and esports markets only (#29971). Read in_scope.realized_pnl."
          },
          "realized_pnl": {
            "type": "number",
            "deprecated": true,
            "x-never-sent": true,
            "description": "Deprecated since 2026-10-27 and never sent. It was native Polymarket realized P&L over every Polymarket market of the wallet, and wallet figures cover sports and esports markets only (#29971). Read in_scope.realized_pnl."
          },
          "pnl_correction": {
            "$ref": "#/components/schemas/PnlCorrection",
            "deprecated": true,
            "x-never-sent": true,
            "description": "Deprecated since 2026-10-27 and never sent. It was the neg-risk conversion correction to the wallet-wide realized_pnl (#29971). Its sports and esports part is inside in_scope.realized_pnl."
          },
          "volume": {
            "type": "number",
            "deprecated": true,
            "x-never-sent": true,
            "description": "Deprecated since 2026-10-27 and never sent. It was full-history USD cash volume over every Polymarket market of the wallet, and wallet figures cover sports and esports markets only (#29971)."
          },
          "markets_traded": {
            "type": "integer",
            "description": "Sports and esports markets on the wallet's record, the same count as in_scope.markets. Since 2026-10-27 (#29971); before, it counted every Polymarket market. Sent exactly when in_scope is."
          },
          "win_rate": {
            "type": "number",
            "description": "The wallet's sports and esports win rate, in_scope.win_rate rounded to four places. Since 2026-10-27 (#29971); before, it covered every Polymarket market. ?category= decides WHICH wallets are listed (the wallet must be ranked in that category); it does not rescope this field. For a per-category record use GET /api/v1/trader/{address}/categories. Omitted when in_scope is omitted or has no win rate."
          },
          "in_scope": {
            "$ref": "#/components/schemas/TraderPnlInScope",
            "description": "Additive (#27859): the wallet's sports and esports record, the same object as GET /api/v1/trader/{address} pnl.in_scope, as of the leaderboard's last refresh. The 0xinsider leaderboard page shows and sorts by in_scope.realized_pnl and in_scope.win_rate. Omitted until 0xinsider has computed the wallet's record; absent means not computed yet, never zero."
          },
          "price_edge": {
            "$ref": "#/components/schemas/LeaderboardPriceEdge",
            "description": "Additive (#32270): the wallet's edge over the price paid on its sports and esports markets, the figures the 0xinsider leaderboard page's Edge column states for the row. sort=edge orders by price_edge.edge. Omitted when the wallet has no settled sports or esports market of $20 or more at a known entry price."
          },
          "strategy_type": {
            "type": "string",
            "description": "Observed trading style identifier. New rows use two_sided, category_focused, high_activity, diversified, mixed, or unclassified, counted over the wallet's sports and esports markets only. Historical identifiers remain readable during normal reclassification; style does not predict skill or intent."
          },
          "platform": {
            "type": "string",
            "enum": ["polymarket"],
            "description": "Provider platform. Always polymarket."
          },
          "last_active": {
            "type": "string",
            "format": "date-time",
            "description": "When the wallet last traded: its most recent recorded trade, as of the leaderboard row's last refresh, which re-reads it hourly, so a new trade can take about an hour to show. It agrees with the activity filter: every wallet listed under activity=inactive last traded more than 30 days ago. Since 2026-11-02 (#32322); before, it carried the time 0xinsider last synced the wallet, usually within the past week whether or not the wallet traded. Omitted when the wallet has no recorded trade."
          }
        }
      },
      "LeaderboardSummary": {
        "type": "object",
        "description": "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.",
        "required": ["ranked_total", "by_grade", "active_30d", "as_of"],
        "properties": {
          "ranked_total": {
            "type": "integer",
            "description": "Ranked wallets on the board: the wallets the unfiltered list pages through."
          },
          "by_grade": {
            "type": "object",
            "description": "Ranked wallets by grade. Every ranked wallet is graded S, A or B, so the three sum to ranked_total.",
            "required": ["S", "A", "B"],
            "properties": {
              "S": {
                "type": "integer"
              },
              "A": {
                "type": "integer"
              },
              "B": {
                "type": "integer"
              }
            }
          },
          "active_30d": {
            "type": "integer",
            "description": "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."
          },
          "as_of": {
            "type": "string",
            "format": "date-time",
            "description": "When the totals were counted, UTC. They are recounted about once a minute while the ranking is current."
          }
        }
      },
      "LeaderboardPriceEdge": {
        "type": "object",
        "description": "Edge over the price paid (#32270): 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.12 is 12 percentage points. A wallet buying at 99 cents that wins every market has an edge of about 0.01. A market bought on both sides counts by its shares: the winning side's share of the shares bought is its hit, the cost over those shares its price.",
        "required": ["markets", "hit_rate", "avg_price", "edge", "status"],
        "properties": {
          "markets": {
            "type": "integer",
            "description": "Settled sports and esports markets of $20 or more at a known entry price that the edge is measured over."
          },
          "hit_rate": {
            "type": "number",
            "description": "Share of those markets whose bought side won, 0-1."
          },
          "avg_price": {
            "type": "number",
            "description": "Mean entry price paid, 0-1."
          },
          "edge": {
            "type": "number",
            "description": "hit_rate minus avg_price, full precision. The value sort=edge orders by."
          },
          "status": {
            "type": "string",
            "enum": ["ranked", "too_few_markets", "sample_mismatch"],
            "description": "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. Only a ranked edge with no hold orders on sort=edge."
          },
          "hold": {
            "type": "string",
            "enum": ["record_incomplete"],
            "description": "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."
          }
        }
      },
      "ContentSearchResult": {
        "type": "object",
        "required": ["content_id", "kind", "slug", "title", "excerpt", "url"],
        "properties": {
          "content_id": {
            "type": "string",
            "description": "Backend-owned stable editorial content identifier."
          },
          "kind": {
            "type": "string",
            "enum": ["learn", "glossary", "comparison", "research", "strategy"],
            "description": "Editorial content kind."
          },
          "slug": {
            "type": "string",
            "description": "Backend-owned content slug."
          },
          "title": {
            "type": "string",
            "description": "Editorial title."
          },
          "excerpt": {
            "type": "string",
            "description": "Search-result excerpt."
          },
          "url": {
            "type": "string",
            "description": "Canonical first-party content URL."
          }
        }
      },
      "MarketSearchResult": {
        "type": "object",
        "required": ["id", "condition_id", "title", "slug", "category", "platform", "status"],
        "properties": {
          "id": {
            "type": "string"
          },
          "condition_id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "slug": {
            "type": ["string", "null"]
          },
          "category": {
            "type": ["string", "null"]
          },
          "platform": {
            "type": ["string", "null"],
            "enum": ["polymarket", null],
            "description": "Provider platform. Always polymarket, or null when the row carries no stored value."
          },
          "status": {
            "type": "string",
            "enum": ["active", "closed"],
            "description": "closed once Polymarket has closed trading or the market has resolved; active otherwise. The same rule labels a market on markets/search, markets/explore and market/{condition_id}/snapshot."
          },
          "event_slug": {
            "type": "string"
          }
        }
      },
      "ExploreMarket": {
        "type": "object",
        "required": [
          "id",
          "condition_id",
          "title",
          "slug",
          "url_slug",
          "image",
          "icon",
          "category",
          "platform",
          "status",
          "volume",
          "liquidity",
          "large_trade_count",
          "whale_trade_count",
          "large_trade_distinct_wallets",
          "whale_distinct_wallets",
          "large_trade_total_usd",
          "whale_total_usd",
          "large_trade_last_at",
          "whale_last_trade_at",
          "end_date",
          "created_at",
          "outcome_yes",
          "token_id_yes",
          "outcome_no",
          "token_id_no",
          "event_slug",
          "smart_score",
          "smart_count",
          "smart_label",
          "sharp_money_as_of",
          "outcome_yes_label",
          "outcome_no_label",
          "outcome_yes_provider_id",
          "outcome_no_provider_id",
          "open_interest",
          "oi_change_pct",
          "price_points",
          "no_price_points",
          "last_price",
          "no_last_price",
          "change_pct_24h",
          "no_change_pct_24h",
          "discover_score",
          "score_components",
          "freshness"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "condition_id": {
            "type": "string"
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "description": "Non-empty market title."
          },
          "slug": {
            "type": ["string", "null"],
            "description": "Provider-native market slug."
          },
          "url_slug": {
            "type": ["string", "null"],
            "description": "First-party market page slug used for internal links."
          },
          "image": {
            "type": ["string", "null"]
          },
          "icon": {
            "type": ["string", "null"]
          },
          "category": {
            "type": ["string", "null"]
          },
          "platform": {
            "type": ["string", "null"],
            "enum": ["polymarket", null],
            "description": "Provider platform. Always polymarket, or null when the row carries no stored value."
          },
          "status": {
            "type": "string",
            "enum": ["active", "closed"],
            "description": "closed once Polymarket has closed trading or the market has resolved; active otherwise. The same rule labels a market on markets/search, markets/explore and market/{condition_id}/snapshot."
          },
          "volume": {
            "type": ["number", "null"],
            "description": "Polymarket's traded-volume figure for the market, as last stored: cumulative taker volume in shares, each counted at its $1 settlement value, not the cash that changed hands (100 shares bought at $0.40 add 100, not 40). It can lag Polymarket's current figure. sort=volume orders by it. Null when unavailable."
          },
          "liquidity": {
            "type": ["number", "null"]
          },
          "large_trade_count": {
            "description": "Canonical key since #16304 (Polymarket's noun is large trade); whale_trade_count is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
            "type": ["integer", "null"]
          },
          "whale_trade_count": {
            "deprecated": true,
            "description": "Deprecated spelling of large_trade_count, emitted beside it with the same value. Sunset 2027-02-01 (#29352): removed from V1 on that date; read large_trade_count.",
            "type": ["integer", "null"]
          },
          "large_trade_distinct_wallets": {
            "description": "Canonical key since #16304; whale_distinct_wallets is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
            "type": ["integer", "null"]
          },
          "whale_distinct_wallets": {
            "deprecated": true,
            "description": "Deprecated spelling of large_trade_distinct_wallets, emitted beside it with the same value. Sunset 2027-02-01 (#29352): removed from V1 on that date; read large_trade_distinct_wallets.",
            "type": ["integer", "null"]
          },
          "large_trade_total_usd": {
            "description": "Canonical key since #16304; whale_total_usd is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
            "type": ["number", "null"]
          },
          "whale_total_usd": {
            "deprecated": true,
            "description": "Deprecated spelling of large_trade_total_usd, emitted beside it with the same value. Sunset 2027-02-01 (#29352): removed from V1 on that date; read large_trade_total_usd.",
            "type": ["number", "null"]
          },
          "large_trade_last_at": {
            "description": "Canonical key since #16304; whale_last_trade_at is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
            "type": ["string", "null"],
            "format": "date-time"
          },
          "whale_last_trade_at": {
            "deprecated": true,
            "description": "Deprecated spelling of large_trade_last_at, emitted beside it with the same value. Sunset 2027-02-01 (#29352): removed from V1 on that date; read large_trade_last_at.",
            "type": ["string", "null"],
            "format": "date-time"
          },
          "end_date": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "created_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "outcome_yes": {
            "type": ["string", "null"]
          },
          "token_id_yes": {
            "type": ["string", "null"],
            "description": "The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the YES outcome; null when unavailable (e.g. unsynced markets)."
          },
          "outcome_no": {
            "type": ["string", "null"]
          },
          "token_id_no": {
            "type": ["string", "null"],
            "description": "The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the NO outcome; null when unavailable (e.g. unsynced markets)."
          },
          "event_slug": {
            "type": ["string", "null"]
          },
          "smart_score": {
            "type": ["number", "null"]
          },
          "smart_count": {
            "type": ["integer", "null"]
          },
          "smart_label": {
            "type": ["string", "null"],
            "description": "The outcome graded money leans toward RELATIVE TO THE PRICE: named only when the graded money's share of a side diverges from that side's price-implied share by at least 10 points, with at least $500 on the leaning side and outside the crowded-side guard. Null when the money sits with the price (no lean), when there is no graded money, or when the price is unavailable. The same rule as the market page."
          },
          "sharp_money_as_of": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When the oldest stored smart-money wallet behind this split (smart_score, smart_count and smart_label) last finished syncing. Graded wallets sync on different schedules, so this is often hours or days ago. Some holdings in the split can come from a Polymarket holder read cached for up to 3 minutes, which this time does not describe. Null when there is no split or a wallet's sync time is unknown."
          },
          "outcome_yes_label": {
            "type": ["string", "null"],
            "description": "Display label for the YES/outcome_index=0 side, enriched from provider outcome metadata when available."
          },
          "outcome_no_label": {
            "type": ["string", "null"],
            "description": "Display label for the NO/outcome_index=1 side, enriched from provider outcome metadata when available."
          },
          "outcome_yes_provider_id": {
            "type": ["integer", "null"],
            "description": "Provider-owned YES/outcome_index=0 identifier when available for trade-ticket wiring."
          },
          "outcome_no_provider_id": {
            "type": ["integer", "null"],
            "description": "Provider-owned NO/outcome_index=1 identifier when available for trade-ticket wiring."
          },
          "open_interest": {
            "type": ["number", "null"]
          },
          "oi_change_pct": {
            "type": ["number", "null"]
          },
          "price_points": {
            "type": ["array", "null"],
            "items": {
              "type": "array",
              "minItems": 2,
              "maxItems": 2,
              "items": {
                "type": "number"
              }
            }
          },
          "no_price_points": {
            "type": ["array", "null"],
            "items": {
              "type": "array",
              "minItems": 2,
              "maxItems": 2,
              "items": {
                "type": "number"
              }
            }
          },
          "last_price": {
            "type": ["number", "null"]
          },
          "no_last_price": {
            "type": ["number", "null"]
          },
          "change_pct_24h": {
            "type": ["number", "null"]
          },
          "no_change_pct_24h": {
            "type": ["number", "null"]
          },
          "discover_score": {
            "type": ["number", "null"],
            "description": "Backend-owned deterministic market discovery score used by the hot sort."
          },
          "score_components": {
            "type": "object",
            "required": [
              "volume_signal",
              "large_trade_signal",
              "whale_signal",
              "liquidity_signal",
              "recency_signal",
              "sharp_money_signal",
              "smart_money_signal",
              "price_move_signal",
              "missing_price_penalty"
            ],
            "properties": {
              "volume_signal": {
                "type": ["number", "null"]
              },
              "large_trade_signal": {
                "description": "Canonical key since #16304; whale_signal is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
                "type": ["number", "null"]
              },
              "whale_signal": {
                "deprecated": true,
                "description": "Deprecated spelling of large_trade_signal, emitted beside it with the same value. Sunset 2027-02-01 (#29352): removed from V1 on that date; read large_trade_signal.",
                "type": ["number", "null"]
              },
              "liquidity_signal": {
                "type": ["number", "null"]
              },
              "recency_signal": {
                "type": ["number", "null"]
              },
              "sharp_money_signal": {
                "description": "Canonical key since #16308; smart_money_signal is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
                "type": ["number", "null"]
              },
              "smart_money_signal": {
                "deprecated": true,
                "description": "Deprecated spelling of sharp_money_signal; emitted beside it with the same value. Sunset 2027-02-01 (#29352): removed from V1 on that date; read sharp_money_signal.",
                "type": ["number", "null"]
              },
              "price_move_signal": {
                "type": ["number", "null"]
              },
              "missing_price_penalty": {
                "type": "number"
              }
            }
          },
          "freshness": {
            "type": "object",
            "required": ["enrichment_status", "price_status"],
            "properties": {
              "enrichment_status": {
                "type": "string",
                "enum": ["available", "unavailable"]
              },
              "price_status": {
                "type": "string",
                "enum": ["available", "unavailable"]
              }
            }
          }
        }
      },
      "ExploreGroup": {
        "type": "object",
        "required": [
          "type",
          "event_slug",
          "parent_title",
          "image",
          "platform",
          "category",
          "markets",
          "rep_volume",
          "rep_large_trades",
          "rep_whales"
        ],
        "properties": {
          "type": {
            "type": "string",
            "const": "group"
          },
          "event_slug": {
            "type": "string"
          },
          "parent_title": {
            "type": "string"
          },
          "image": {
            "type": ["string", "null"]
          },
          "platform": {
            "type": ["string", "null"],
            "enum": ["polymarket", null],
            "description": "Provider platform. Always polymarket, or null when the row carries no stored value."
          },
          "category": {
            "type": ["string", "null"]
          },
          "markets": {
            "type": "array",
            "maxItems": 12,
            "description": "Markets in the event cluster, ranked by volume with condition_id as the tie-breaker. The selected representative is retained within the 12-market cap.",
            "items": {
              "$ref": "#/components/schemas/ExploreMarket"
            }
          },
          "rep_volume": {
            "type": ["number", "null"],
            "description": "The volume of the group's highest-volume market, which is markets[0]: the same figure as that market's volume, Polymarket's cumulative taker volume in shares rather than cash. Null when unavailable."
          },
          "rep_large_trades": {
            "description": "Canonical key since #16304; rep_whales is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
            "type": ["integer", "null"]
          },
          "rep_whales": {
            "deprecated": true,
            "description": "Deprecated spelling of rep_large_trades, emitted beside it with the same value. Sunset 2027-02-01 (#29352): removed from V1 on that date; read rep_large_trades.",
            "type": ["integer", "null"]
          }
        }
      },
      "ExploreStandalone": {
        "type": "object",
        "required": ["type", "market"],
        "properties": {
          "type": {
            "type": "string",
            "const": "standalone"
          },
          "market": {
            "$ref": "#/components/schemas/ExploreMarket"
          }
        }
      },
      "ExploreFacetValue": {
        "type": "object",
        "required": ["value", "label", "count"],
        "properties": {
          "value": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          }
        }
      },
      "ExploreFacets": {
        "type": "object",
        "required": ["categories", "platforms"],
        "properties": {
          "categories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExploreFacetValue"
            }
          },
          "platforms": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExploreFacetValue"
            }
          }
        }
      },
      "ExploreEntry": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/ExploreGroup"
          },
          {
            "$ref": "#/components/schemas/ExploreStandalone"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "group": "#/components/schemas/ExploreGroup",
            "standalone": "#/components/schemas/ExploreStandalone"
          }
        }
      },
      "MarketHolder": {
        "type": "object",
        "required": [
          "id",
          "trader_id",
          "address",
          "name",
          "side",
          "token_id",
          "grade",
          "shares",
          "current_value_usd",
          "last_traded_at",
          "category_win_rate_status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Composite `pos_<wallet>:<condition_id>:<outcome_index>`, the same id `GET /api/v1/positions` gives this leg."
          },
          "trader_id": {
            "type": "string",
            "description": "`trd_`-prefixed trader id, accepted by `GET /api/v1/trader/{address}`."
          },
          "address": {
            "type": "string",
            "description": "Lowercased proxy wallet."
          },
          "name": {
            "type": ["string", "null"],
            "description": "Polymarket's public display name from the same holder snapshot; null for a private wallet, which the provider redacts at the source."
          },
          "side": {
            "type": "string",
            "enum": ["YES", "NO"],
            "description": "The outcome this wallet nets to. A wallet holding both outcomes is listed once, on its net side; see `other_outcome_shares`."
          },
          "token_id": {
            "type": ["string", "null"],
            "description": "Polymarket CLOB token id (ERC1155 asset id, decimal string) for `side`; null when the market has no stored token id."
          },
          "grade": {
            "type": ["string", "null"],
            "enum": ["S", "A", "B", null],
            "x-narrowed": true,
            "description": "All-time trader grade. This route lists the S/A/B cohort only, the same cohort a Pick of the Day roster lists."
          },
          "shares": {
            "type": "number",
            "description": "Shares held on `side`, from the complete provider scan."
          },
          "current_value_usd": {
            "type": ["number", "null"],
            "description": "Polymarket's own currentValue for this leg, in USD. Null when the snapshot predates the value map."
          },
          "other_outcome_shares": {
            "type": "number",
            "description": "Shares on the other outcome when the wallet holds both. Absent when the wallet is one-sided."
          },
          "last_traded_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "The wallet's last recorded trade anywhere, null when unknown."
          },
          "category_win_rate": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "This wallet's win rate in the market's canonical category (`market.category`): the share of its settled markets in that category (it closed its position by selling out, or the market resolved) whose realized P&L closed positive, as a 0..1 fraction. Present only with `category_win_rate_status` = `measured`. The same read `GET /api/v1/trader/{address}/categories` serves per wallet."
          },
          "category_win_record": {
            "type": "object",
            "required": ["wins", "decided"],
            "properties": {
              "wins": {
                "type": "integer",
                "minimum": 0,
                "description": "Settled markets in the category that this wallet closed with a profit."
              },
              "decided": {
                "type": "integer",
                "minimum": 0,
                "description": "Settled markets in the category that this wallet closed with a profit or a loss. A market resolved at zero realized P&L is in neither count."
              }
            },
            "description": "The two counts `category_win_rate` is the ratio of, from the same row: `wins / decided` equals the rate. Every settled Polymarket market the wallet traded (it closed its position by selling out, or the market resolved) in the market's canonical category, at any position size, rebuilt daily. Present only with `category_win_rate_status` = `measured`."
          },
          "category_avg_price": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "The wallet's average entry price in the market's canonical category, as a 0..1 fraction of $1 (0.98 is 98 cents). Its sample is the wallet's markets in that category that resolved to a winning side, of $20 or more where it bought one side at a known price, so it can differ from the `category_win_record` sample. A wallet that buys near-certain outcomes wins almost every time, so read the win rate beside this price. Present only with `category_win_rate_status` = `measured`, and only when that sample has at least 5 markets. When `category_win_rate_game` is present the price is still the whole `category` bucket's: this field has no per-game or per-league price. Absent otherwise and on payloads predating the field."
          },
          "category_win_rate_game": {
            "type": "string",
            "description": "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."
          },
          "category_win_rate_status": {
            "type": "string",
            "enum": ["measured", "not_enough_data", "unavailable", "untracked"],
            "description": "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."
          },
          "category_evidence": {
            "$ref": "#/components/schemas/HolderCategoryEvidence"
          },
          "wallet_age_days": {
            "type": ["number", "null"],
            "description": "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."
          },
          "is_new_wallet": {
            "type": "boolean",
            "description": "True when the wallet's first trade was under 30 days ago."
          },
          "markets_traded": {
            "type": ["integer", "null"],
            "description": "Distinct markets the wallet has traded."
          },
          "is_bot": {
            "type": "boolean",
            "description": "True when the wallet is flagged as automated."
          },
          "x_username": {
            "type": ["string", "null"],
            "description": "The wallet's X handle without the @, when linked."
          }
        }
      },
      "MarketHoldersMarket": {
        "type": "object",
        "required": [
          "id",
          "condition_id",
          "title",
          "category",
          "outcome_yes",
          "outcome_no",
          "token_id_yes",
          "token_id_no",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "`mkt_`-prefixed market id."
          },
          "condition_id": {
            "type": "string"
          },
          "title": {
            "type": ["string", "null"]
          },
          "slug": {
            "type": "string"
          },
          "event_slug": {
            "type": "string"
          },
          "category": {
            "type": ["string", "null"],
            "description": "The canonical category bucket `category_win_rate` is measured in."
          },
          "outcome_yes": {
            "type": ["string", "null"]
          },
          "outcome_no": {
            "type": ["string", "null"]
          },
          "token_id_yes": {
            "type": ["string", "null"]
          },
          "token_id_no": {
            "type": ["string", "null"]
          },
          "end_date": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "type": "string",
            "enum": ["open", "closed", "resolved"],
            "description": "A settled market's roster is whatever the provider still lists as open; it empties as holders redeem."
          }
        }
      },
      "MarketHoldersScan": {
        "type": "object",
        "required": ["source", "complete", "fetched_at", "wallet_count"],
        "properties": {
          "source": {
            "type": "string",
            "enum": ["cached", "live"],
            "description": "`cached`: the shared holder snapshot, at most 180 s old at compute time. `live`: the provider answered a fresh complete walk for this compute."
          },
          "complete": {
            "type": "boolean",
            "description": "Always true on a served roster. An incomplete or unstable scan is a 503, never a partial list."
          },
          "fetched_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When the provider walk that produced the holder population finished."
          },
          "wallet_count": {
            "type": "integer",
            "description": "Every distinct wallet the complete walk saw with open shares, graded or not. The roster lists the graded S/A/B subset."
          }
        }
      },
      "MarketHoldersSideGrades": {
        "type": "object",
        "required": ["s", "a", "b"],
        "properties": {
          "s": {
            "type": "integer"
          },
          "a": {
            "type": "integer"
          },
          "b": {
            "type": "integer"
          }
        }
      },
      "MarketHoldersSideGradeUsd": {
        "type": "object",
        "required": ["s", "a", "b"],
        "description": "Polymarket currentValue in USD per grade on one side, over the same wallets as that side's usd total. Each value is rounded to the cent after summing, so s + a + b can differ from the side total by up to 2 cents.",
        "properties": {
          "s": {
            "type": "number",
            "description": "USD held by S-grade wallets netting this side."
          },
          "a": {
            "type": "number",
            "description": "USD held by A-grade wallets netting this side."
          },
          "b": {
            "type": "number",
            "description": "USD held by B-grade wallets netting this side."
          }
        }
      },
      "MarketHoldersTotals": {
        "type": "object",
        "required": [
          "graded_count",
          "yes_count",
          "no_count",
          "yes_shares",
          "no_shares",
          "yes_usd",
          "no_usd",
          "yes_grades",
          "no_grades",
          "yes_grade_usd",
          "no_grade_usd"
        ],
        "description": "Roster totals BEFORE any `outcome` or `min_grade` filter, so a page always knows the whole market it was cut from.",
        "properties": {
          "graded_count": {
            "type": "integer",
            "description": "Distinct graded wallets with net exposure; a two-sided wallet counts once."
          },
          "yes_count": {
            "type": "integer"
          },
          "no_count": {
            "type": "integer"
          },
          "yes_shares": {
            "type": "number"
          },
          "no_shares": {
            "type": "number"
          },
          "yes_usd": {
            "type": "number",
            "description": "Polymarket currentValue summed over the graded wallets netting YES."
          },
          "no_usd": {
            "type": "number",
            "description": "Polymarket currentValue summed over the graded wallets netting NO."
          },
          "yes_grades": {
            "$ref": "#/components/schemas/MarketHoldersSideGrades"
          },
          "no_grades": {
            "$ref": "#/components/schemas/MarketHoldersSideGrades"
          },
          "yes_grade_usd": {
            "$ref": "#/components/schemas/MarketHoldersSideGradeUsd",
            "description": "yes_usd split by grade: where the S, A and B money on YES sits."
          },
          "no_grade_usd": {
            "$ref": "#/components/schemas/MarketHoldersSideGradeUsd",
            "description": "no_usd split by grade: where the S, A and B money on NO sits."
          }
        }
      },
      "MarketTopHolder": {
        "type": "object",
        "required": [
          "rank",
          "trader_id",
          "address",
          "name",
          "grade",
          "shares",
          "current_value_usd",
          "avg_entry_price",
          "position_realized_pnl",
          "position_unrealized_pnl",
          "position_total_pnl",
          "in_scope_realized_pnl",
          "in_scope_volume",
          "strategy_type",
          "last_traded_at"
        ],
        "properties": {
          "rank": {
            "type": "integer",
            "minimum": 1,
            "description": "1-based position on this outcome, by shares."
          },
          "trader_id": {
            "type": "string",
            "description": "`trd_`-prefixed trader id, accepted by `GET /api/v1/trader/{address}`."
          },
          "address": {
            "type": "string",
            "description": "Lowercased proxy wallet."
          },
          "name": {
            "type": ["string", "null"],
            "description": "The wallet's display name; null when it shows none."
          },
          "grade": {
            "type": ["string", "null"],
            "enum": ["S", "A", "B", "C", "D", "F", null],
            "description": "All-time trader grade, S to F. Null for a wallet 0xinsider has not graded: this route lists every holder whatever its grade."
          },
          "shares": {
            "type": "number",
            "description": "Shares held on this outcome."
          },
          "current_value_usd": {
            "type": ["number", "null"],
            "description": "Polymarket's current value of this position, in USD. Null when the provider served none."
          },
          "avg_entry_price": {
            "type": ["number", "null"],
            "description": "Average price paid for the shares still held, as a 0..1 fraction of $1. Null when the provider served none.",
            "minimum": 0,
            "maximum": 1
          },
          "other_outcome_shares": {
            "type": "number",
            "description": "Shares on the other outcome when the wallet holds both; the wallet is then listed on both sides. Absent when it is one-sided."
          },
          "position_realized_pnl": {
            "type": ["number", "null"],
            "description": "Polymarket's realized P&L of this position (sells and redemptions), in USD. Null when the provider served no economics for the row."
          },
          "position_unrealized_pnl": {
            "type": ["number", "null"],
            "description": "Polymarket's mark-to-market P&L of the shares still held, in USD. On a resolved market the mark is the settlement price."
          },
          "position_total_pnl": {
            "type": ["number", "null"],
            "description": "`position_realized_pnl` plus `position_unrealized_pnl`, in USD."
          },
          "in_scope_realized_pnl": {
            "type": ["number", "null"],
            "description": "The wallet's realized P&L on sports and esports markets, in USD, the figure on its 0xinsider profile. Null until 0xinsider has computed the record, never 0 in its place, and null for every row when `profiles_status` is `unavailable`."
          },
          "in_scope_volume": {
            "type": ["number", "null"],
            "description": "The wallet's volume traded on sports and esports markets, in USD. Null under the same rule as `in_scope_realized_pnl`."
          },
          "strategy_type": {
            "type": ["string", "null"],
            "description": "The wallet's stored trading-style label (see Wallet trading styles); null when it has none."
          },
          "last_traded_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "The wallet's last recorded trade anywhere, null when unknown."
          },
          "category_win_rate": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "This wallet's win rate in the market's canonical category (`market.category`): the share of its settled markets in that category (it closed its position by selling out, or the market resolved) whose realized P&L closed positive, as a 0..1 fraction. Present only with `category_win_rate_status` = `measured`. The same read `GET /api/v1/trader/{address}/categories` serves per wallet."
          },
          "category_win_record": {
            "type": "object",
            "required": ["wins", "decided"],
            "properties": {
              "wins": {
                "type": "integer",
                "minimum": 0,
                "description": "Settled markets in the category that this wallet closed with a profit."
              },
              "decided": {
                "type": "integer",
                "minimum": 0,
                "description": "Settled markets in the category that this wallet closed with a profit or a loss. A market resolved at zero realized P&L is in neither count."
              }
            },
            "description": "The two counts `category_win_rate` is the ratio of, from the same row: `wins / decided` equals the rate. Every settled Polymarket market the wallet traded (it closed its position by selling out, or the market resolved) in the market's canonical category, at any position size, rebuilt daily. Present only with `category_win_rate_status` = `measured`."
          },
          "category_avg_price": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "The wallet's average entry price in the market's canonical category, as a 0..1 fraction of $1 (0.98 is 98 cents). Its sample is the wallet's markets in that category that resolved to a winning side, of $20 or more where it bought one side at a known price, so it can differ from the `category_win_record` sample. A wallet that buys near-certain outcomes wins almost every time, so read the win rate beside this price. Present only with `category_win_rate_status` = `measured`, and only when that sample has at least 5 markets. When `category_win_rate_game` is present the price is still the whole `category` bucket's: this field has no per-game or per-league price. Absent otherwise and on payloads predating the field."
          },
          "category_win_rate_game": {
            "type": "string",
            "description": "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."
          },
          "category_win_rate_status": {
            "type": "string",
            "enum": ["measured", "not_enough_data", "unavailable", "untracked"],
            "description": "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."
          },
          "wallet_age_days": {
            "type": ["number", "null"],
            "description": "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."
          },
          "is_new_wallet": {
            "type": "boolean",
            "description": "True when the wallet's first trade was under 30 days ago."
          },
          "markets_traded": {
            "type": ["integer", "null"],
            "description": "Distinct markets the wallet has traded."
          },
          "is_bot": {
            "type": "boolean",
            "description": "True when the wallet is flagged as automated."
          },
          "x_username": {
            "type": ["string", "null"],
            "description": "The wallet's X handle without the @, when linked."
          }
        }
      },
      "MarketTopHolders": {
        "type": "object",
        "required": ["market", "yes", "no", "totals", "profiles_status", "source_stale"],
        "properties": {
          "market": {
            "$ref": "#/components/schemas/MarketHoldersMarket"
          },
          "yes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MarketTopHolder"
            },
            "description": "The largest YES holders, by shares, up to `limit`."
          },
          "no": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MarketTopHolder"
            },
            "description": "The largest NO holders, by shares, up to `limit`."
          },
          "totals": {
            "$ref": "#/components/schemas/MarketTopHoldersTotals"
          },
          "profiles_status": {
            "type": "string",
            "enum": ["available", "unavailable"],
            "description": "`unavailable` when the wallet record read failed: `in_scope_realized_pnl`, `in_scope_volume` and `strategy_type` are then null for every row because they were not read, not because they are unknown."
          },
          "category_records_as_of": {
            "type": "string",
            "format": "date-time",
            "description": "When the daily pass behind the rows' category win records began. Absent when the market has no category or the read answered no row."
          },
          "computed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When this holder sample was built."
          },
          "positions_as_of": {
            "type": "string",
            "format": "date-time",
            "description": "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."
          },
          "source_stale": {
            "type": "boolean",
            "description": "`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."
          }
        }
      },
      "MarketTopHoldersTotals": {
        "type": "object",
        "required": ["yes_count", "no_count", "yes_shares", "no_shares", "sample_cap"],
        "properties": {
          "yes_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Holders in the YES sample, before `limit`. Equal to `sample_cap` means that many or more."
          },
          "no_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Holders in the NO sample, before `limit`."
          },
          "yes_shares": {
            "type": "number",
            "description": "Shares summed over the YES sample."
          },
          "no_shares": {
            "type": "number",
            "description": "Shares summed over the NO sample."
          },
          "sample_cap": {
            "type": "integer",
            "minimum": 0,
            "description": "The most holders the sample keeps per outcome (100)."
          }
        }
      },
      "MarketFlow": {
        "type": "object",
        "required": ["market", "sharp_money", "smart_money", "timeframe"],
        "properties": {
          "market": {
            "type": "object",
            "required": ["id", "condition_id", "title", "slug", "category", "platform"],
            "properties": {
              "id": {
                "type": "string"
              },
              "condition_id": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "slug": {
                "type": ["string", "null"]
              },
              "category": {
                "type": ["string", "null"]
              },
              "platform": {
                "type": ["string", "null"],
                "enum": ["polymarket", null],
                "description": "Provider platform. Always polymarket, or null when the row carries no stored value."
              }
            }
          },
          "sharp_money": {
            "type": "object",
            "description": "Outcome-aware flow from all tracked whale trades in the window, without a grade filter. BUY YES and SELL NO add net exposure; BUY NO and SELL YES subtract it. Gross buy/sell volumes count both outcomes. Top positions are separately graded. Direction uses unrounded net: negative is NO, otherwise YES; the zero tie-break is not conviction. Canonical; smart_money is a deprecated byte-identical alias.",
            "required": [
              "net_flow_usd",
              "direction",
              "token_id",
              "large_trade_count",
              "whale_trade_count",
              "buy_volume_usd",
              "sell_volume_usd",
              "top_positions",
              "oldest_snapshot_as_of"
            ],
            "properties": {
              "net_flow_usd": {
                "type": "number"
              },
              "direction": {
                "type": "string",
                "enum": ["YES", "NO"]
              },
              "token_id": {
                "type": ["string", "null"],
                "description": "The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets)."
              },
              "large_trade_count": {
                "description": "Canonical key since #16304 (Polymarket's noun is large trade); whale_trade_count is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
                "type": "integer"
              },
              "whale_trade_count": {
                "deprecated": true,
                "description": "Deprecated spelling of large_trade_count, emitted beside it with the same value. Sunset 2027-02-01 (#29352): removed from V1 on that date; read large_trade_count.",
                "type": "integer"
              },
              "buy_volume_usd": {
                "type": "number"
              },
              "sell_volume_usd": {
                "type": "number"
              },
              "top_positions": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "id",
                    "address",
                    "username",
                    "grade",
                    "side",
                    "token_id",
                    "size_usd"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "address": {
                      "type": "string"
                    },
                    "username": {
                      "type": ["string", "null"]
                    },
                    "grade": {
                      "type": ["string", "null"],
                      "enum": ["S", "A", "B", "C", "D", "F", null]
                    },
                    "side": {
                      "type": "string",
                      "enum": ["YES", "NO"]
                    },
                    "token_id": {
                      "type": ["string", "null"],
                      "description": "The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets)."
                    },
                    "size_usd": {
                      "type": "number"
                    }
                  }
                }
              },
              "oldest_snapshot_as_of": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "Age of the oldest stored position snapshot behind top_positions: the minimum wallet sync clock over the positions this body publishes. The roster is a stored read rather than a live one, and graded wallets sit on different sync tiers, so this names how current the whole roster is; the response is no fresher than this timestamp. Null when the roster is empty or no published position carries a sync clock. It does not date net_flow_usd, the volumes or the trade counts, which come from large-trade event times."
              }
            }
          },
          "smart_money": {
            "type": "object",
            "deprecated": true,
            "description": "Deprecated alias of sharp_money; byte-identical. Sunset 2027-02-01 (#29352): removed from V1 on that date; read sharp_money.",
            "required": [
              "net_flow_usd",
              "direction",
              "token_id",
              "large_trade_count",
              "whale_trade_count",
              "buy_volume_usd",
              "sell_volume_usd",
              "top_positions",
              "oldest_snapshot_as_of"
            ],
            "properties": {
              "net_flow_usd": {
                "type": "number"
              },
              "direction": {
                "type": "string",
                "enum": ["YES", "NO"]
              },
              "token_id": {
                "type": ["string", "null"],
                "description": "The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets)."
              },
              "large_trade_count": {
                "description": "Canonical key since #16304 (Polymarket's noun is large trade); whale_trade_count is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
                "type": "integer"
              },
              "whale_trade_count": {
                "deprecated": true,
                "description": "Deprecated spelling of large_trade_count, emitted beside it with the same value. Sunset 2027-02-01 (#29352): removed from V1 on that date; read large_trade_count.",
                "type": "integer"
              },
              "buy_volume_usd": {
                "type": "number"
              },
              "sell_volume_usd": {
                "type": "number"
              },
              "top_positions": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "id",
                    "address",
                    "username",
                    "grade",
                    "side",
                    "token_id",
                    "size_usd"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "address": {
                      "type": "string"
                    },
                    "username": {
                      "type": ["string", "null"]
                    },
                    "grade": {
                      "type": ["string", "null"],
                      "enum": ["S", "A", "B", "C", "D", "F", null]
                    },
                    "side": {
                      "type": "string",
                      "enum": ["YES", "NO"]
                    },
                    "token_id": {
                      "type": ["string", "null"],
                      "description": "The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets)."
                    },
                    "size_usd": {
                      "type": "number"
                    }
                  }
                }
              },
              "oldest_snapshot_as_of": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "Age of the oldest stored position snapshot behind top_positions: the minimum wallet sync clock over the positions this body publishes. The roster is a stored read rather than a live one, and graded wallets sit on different sync tiers, so this names how current the whole roster is; the response is no fresher than this timestamp. Null when the roster is empty or no published position carries a sync clock. It does not date net_flow_usd, the volumes or the trade counts, which come from large-trade event times."
              }
            }
          },
          "timeframe": {
            "type": "string"
          }
        }
      },
      "SmartMoneyFlowMarket": {
        "type": "object",
        "required": ["market", "sharp_money", "smart_money", "timeframe"],
        "properties": {
          "market": {
            "type": "object",
            "required": ["id", "condition_id", "title", "slug", "category", "platform"],
            "properties": {
              "id": {
                "type": "string"
              },
              "condition_id": {
                "type": "string"
              },
              "title": {
                "type": ["string", "null"]
              },
              "slug": {
                "type": ["string", "null"]
              },
              "category": {
                "type": ["string", "null"]
              },
              "platform": {
                "type": ["string", "null"],
                "enum": ["polymarket", null],
                "description": "Provider platform. Always polymarket, or null when the row carries no stored value."
              }
            }
          },
          "sharp_money": {
            "type": "object",
            "description": "Sharp-money flow aggregate for the market (canonical; smart_money is a deprecated byte-identical alias).",
            "required": [
              "net_flow_usd",
              "direction",
              "token_id",
              "large_trade_count",
              "whale_trade_count",
              "buy_volume_usd",
              "sell_volume_usd"
            ],
            "properties": {
              "net_flow_usd": {
                "type": "number"
              },
              "direction": {
                "type": "string",
                "enum": ["YES", "NO"]
              },
              "token_id": {
                "type": ["string", "null"],
                "description": "The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets)."
              },
              "large_trade_count": {
                "description": "Canonical key since #16304 (Polymarket's noun is large trade); whale_trade_count is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
                "type": "integer"
              },
              "whale_trade_count": {
                "deprecated": true,
                "description": "Deprecated spelling of large_trade_count, emitted beside it with the same value. Sunset 2027-02-01 (#29352): removed from V1 on that date; read large_trade_count.",
                "type": "integer"
              },
              "buy_volume_usd": {
                "type": "number"
              },
              "sell_volume_usd": {
                "type": "number"
              }
            }
          },
          "smart_money": {
            "type": "object",
            "deprecated": true,
            "description": "Deprecated alias of sharp_money; byte-identical. Sunset 2027-02-01 (#29352): removed from V1 on that date; read sharp_money.",
            "required": [
              "net_flow_usd",
              "direction",
              "token_id",
              "large_trade_count",
              "whale_trade_count",
              "buy_volume_usd",
              "sell_volume_usd"
            ],
            "properties": {
              "net_flow_usd": {
                "type": "number"
              },
              "direction": {
                "type": "string",
                "enum": ["YES", "NO"]
              },
              "token_id": {
                "type": ["string", "null"],
                "description": "The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets)."
              },
              "large_trade_count": {
                "description": "Canonical key since #16304 (Polymarket's noun is large trade); whale_trade_count is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
                "type": "integer"
              },
              "whale_trade_count": {
                "deprecated": true,
                "description": "Deprecated spelling of large_trade_count, emitted beside it with the same value. Sunset 2027-02-01 (#29352): removed from V1 on that date; read large_trade_count.",
                "type": "integer"
              },
              "buy_volume_usd": {
                "type": "number"
              },
              "sell_volume_usd": {
                "type": "number"
              }
            }
          },
          "timeframe": {
            "type": "string"
          }
        }
      },
      "MarketSnapshotFreshness": {
        "type": "object",
        "required": ["status", "source"],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["fresh", "stale", "available", "not_live", "unavailable"]
          },
          "source": {
            "type": "string"
          },
          "as_of": {
            "type": "string",
            "format": "date-time"
          },
          "stale_after_s": {
            "type": "integer",
            "description": "Age-relative freshness bound when known. Omitted for live_sports: its as_of records compute start, while its two-second freshness marker starts at publication."
          },
          "reason": {
            "type": "string"
          }
        }
      },
      "MarketSnapshotTopOfBook": {
        "type": "object",
        "required": ["status", "source"],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["available", "unavailable"],
            "x-narrowed": true
          },
          "source": {
            "type": "string"
          },
          "best_bid": {
            "type": "number"
          },
          "best_ask": {
            "type": "number"
          },
          "spread_bps": {
            "type": "integer"
          },
          "bid_depth_usdc": {
            "description": "USD (price times size) on bids at or above the midpoint minus 0.02, from the whole book, rounded to the cent. The props filter min_book_usd_within_2c compares the unrounded sums, which expand=quotes serves as book_depth_within_2c. Absent when we hold no depth for the book.",
            "type": "number"
          },
          "ask_depth_usdc": {
            "description": "USD (price times size) on asks at or below the midpoint plus 0.02, from the whole book, rounded to the cent. The props filter min_book_usd_within_2c compares the unrounded sums, which expand=quotes serves as book_depth_within_2c. Absent when we hold no depth for the book.",
            "type": "number"
          },
          "reason": {
            "type": "string"
          }
        }
      },
      "MarketSnapshotTrust": {
        "type": "object",
        "description": "Price and spread trust metadata returned only when GET /api/v1/market/{condition_id}/snapshot includes expand=trust.",
        "required": ["current_price", "spread_bps"],
        "properties": {
          "current_price": {
            "$ref": "#/components/schemas/TrustMetadata"
          },
          "spread_bps": {
            "$ref": "#/components/schemas/TrustMetadata"
          }
        }
      },
      "MarketSnapshot": {
        "type": "object",
        "required": ["market", "outcomes", "liquidity", "sports", "freshness", "settlement"],
        "properties": {
          "market": {
            "type": "object",
            "required": [
              "id",
              "condition_id",
              "provider",
              "title",
              "slug",
              "page_slug",
              "event_slug",
              "category",
              "status",
              "description",
              "image",
              "series_slug",
              "market_type",
              "market_result",
              "created_at",
              "end_date",
              "resolved_at"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "condition_id": {
                "type": "string"
              },
              "provider": {
                "type": "string"
              },
              "title": {
                "type": ["string", "null"]
              },
              "slug": {
                "type": ["string", "null"]
              },
              "page_slug": {
                "type": ["string", "null"]
              },
              "event_slug": {
                "type": ["string", "null"]
              },
              "category": {
                "type": ["string", "null"]
              },
              "status": {
                "type": "string",
                "enum": ["active", "closed"],
                "description": "closed once Polymarket has closed trading or the market has resolved; active otherwise. The same rule labels a market on markets/search, markets/explore and market/{condition_id}/snapshot."
              },
              "description": {
                "type": ["string", "null"]
              },
              "image": {
                "type": ["string", "null"]
              },
              "series_slug": {
                "type": ["string", "null"],
                "description": "Polymarket series slug from the canonical identity row, null when unavailable. A sports series identifies a league and must not be used as a per-matchup grouping key."
              },
              "market_type": {
                "deprecated": true,
                "type": ["string", "null"],
                "description": "Always null. Deprecated (#24169): 0xinsider has never stored a value for this field. The key stays on the wire until its sunset on 2027-02-01 (#29352), when it is removed; do not read it."
              },
              "market_result": {
                "deprecated": true,
                "type": ["string", "null"],
                "description": "Always null. Deprecated (#24169): 0xinsider stores no value for this field on a Polymarket market. The key stays on the wire until its sunset on 2027-02-01 (#29352), when it is removed; do not read it. market.status and market.resolved_at say whether the market has closed or resolved."
              },
              "created_at": {
                "type": ["string", "null"],
                "format": "date-time"
              },
              "end_date": {
                "type": ["string", "null"],
                "format": "date-time"
              },
              "resolved_at": {
                "type": ["string", "null"],
                "format": "date-time"
              }
            }
          },
          "outcomes": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["side", "label", "top_of_book"],
              "properties": {
                "side": {
                  "type": "string",
                  "enum": ["yes", "no"]
                },
                "label": {
                  "type": "string"
                },
                "token_id": {
                  "type": "string"
                },
                "current_price": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1,
                  "description": "The outcome's display price, the probability Polymarket shows for it: the midpoint of the cached top of book when the spread is at most 0.10, otherwise the token's last trade price. Omitted when neither is known, including a book wider than 0.10 with no last trade on record; top_of_book still carries that book's best_bid and best_ask. expand=trust explains a missing value in trust.current_price."
                },
                "top_of_book": {
                  "$ref": "#/components/schemas/MarketSnapshotTopOfBook"
                }
              }
            }
          },
          "liquidity": {
            "type": "object",
            "required": [
              "source",
              "volume_usd",
              "liquidity_usd",
              "volume_24h_usd",
              "volume_24h_as_of",
              "last_price"
            ],
            "properties": {
              "source": {
                "type": "string"
              },
              "volume_usd": {
                "type": ["number", "null"],
                "description": "Polymarket's traded-volume figure for the market, as last stored: cumulative taker volume in shares, each counted at its $1 settlement value, not the cash that changed hands (100 shares bought at $0.40 add 100, not 40). It can lag Polymarket's current figure. The name ends in _usd because Polymarket prints this figure with a dollar sign; it is a share count. Null when unavailable."
              },
              "liquidity_usd": {
                "type": ["number", "null"]
              },
              "volume_24h_usd": {
                "type": ["number", "null"],
                "description": "Polymarket's taker volume over the 24 hours before volume_24h_as_of, in shares, each counted at its $1 settlement value, not the cash that changed hands (100 shares bought at $0.40 add 100, not 40). The name ends in _usd because Polymarket prints volume with a dollar sign; it is a share count. Null when Polymarket does not report one: it omits the figure on closed markets and on open markets with no trades in the last 24 hours."
              },
              "volume_24h_as_of": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "When 0xinsider read volume_24h_usd from Polymarket; the figure covers the 24 hours before this time. Null exactly when volume_24h_usd is null."
              },
              "last_price": {
                "type": ["number", "null"],
                "description": "Always null. Polymarket snapshot prices come from outcome top-of-book midpoints."
              }
            }
          },
          "sports": {
            "type": "object",
            "required": ["status", "source"],
            "properties": {
              "status": {
                "type": "string",
                "enum": ["fresh", "stale", "not_live", "unavailable"],
                "x-narrowed": true
              },
              "source": {
                "type": "string"
              },
              "live_match_key": {
                "type": "string"
              },
              "live_league_key": {
                "type": "string"
              },
              "live_score": {
                "description": "Live-score period and elapsed may be omitted when unavailable (older responses use null). A score entry may omit full_name when it equals team; fall back to team. A score entry's side (home or away) is the provider's home/away designation of that team, omitted when the provider gives none; the order of scores states no side. Distinct aliases and score admission markers are preserved. For live esports, scores[].map_score retains an available pair through an update omitting both sides only within the same live map, series format and series totals. Map changes and final state follow current provider updates; absent detail remains unavailable. Optional tennis_points supplies independently sourced current-game points and serving side; absence means unavailable. Compatible unexpired tennis_points survives temporary supplemental snapshot unavailability or contention; expiry and set/game mismatch still clear it.",
                "allOf": [
                  {
                    "type": "object"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "tennis_points": {
                        "$ref": "#/components/schemas/TennisPoints"
                      }
                    }
                  }
                ]
              },
              "reason": {
                "type": "string"
              }
            }
          },
          "freshness": {
            "type": "object",
            "required": ["market_data", "top_of_book", "live_sports"],
            "properties": {
              "market_data": {
                "$ref": "#/components/schemas/MarketSnapshotFreshness"
              },
              "top_of_book": {
                "$ref": "#/components/schemas/MarketSnapshotFreshness"
              },
              "live_sports": {
                "$ref": "#/components/schemas/MarketSnapshotFreshness",
                "description": "Freshness requires the dedicated two-second post-publication marker to match the retained vintage and non-invalidated data timestamp; timestamp presence alone is insufficient. as_of records compute start, so stale_after_s is omitted rather than implying as_of plus two seconds. Missing membership is not_live only in a fresh source; stale membership remains stale and unreadable source data is unavailable. Repeated lookups reuse the shared payload and typed index for an unchanged generation."
              }
            }
          },
          "trust": {
            "$ref": "#/components/schemas/MarketSnapshotTrust",
            "description": "Price and spread trust metadata. Present only when expand=trust or expand[]=trust is requested."
          },
          "settlement": {
            "description": "How Polymarket's oracle settled or is settling this market, the block GET /api/v1/games/{event_slug}/markets serves, read from the store of the market's event (a child event's market: its game's). It never waits for Polymarket: with nothing stored a settled market reads its recorded settlement, and any other reads status unavailable while the read starts. market.market_result stays null; read settlement.result.",
            "type": "object",
            "required": [
              "status",
              "oracle_status",
              "settled",
              "payouts",
              "result",
              "winning_outcome_index",
              "was_disputed",
              "resolved_at",
              "expected_settlement_time",
              "settlement_time_basis",
              "proposed_answer",
              "observed_at"
            ],
            "properties": {
              "expected_settlement_time": {
                "type": ["string", "null"],
                "format": "date-time"
              },
              "observed_at": {
                "type": ["string", "null"],
                "format": "date-time"
              },
              "oracle_status": {
                "type": ["string", "null"]
              },
              "payouts": {
                "type": ["array", "null"],
                "items": {
                  "type": "integer"
                }
              },
              "proposed_answer": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": ["outcome_0", "outcome_1", "split", "too_early"]
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "resolved_at": {
                "type": ["string", "null"],
                "format": "date-time"
              },
              "result": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": ["outcome", "split"]
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "settled": {
                "type": ["boolean", "null"]
              },
              "settlement_time_basis": {
                "type": ["string", "null"]
              },
              "status": {
                "type": "string",
                "enum": ["observed", "not_posed", "unavailable"]
              },
              "was_disputed": {
                "type": ["boolean", "null"]
              },
              "winning_outcome_index": {
                "type": ["integer", "null"]
              }
            }
          }
        }
      },
      "SuspiciousTrade": {
        "type": "object",
        "required": [
          "id",
          "suspicion_score",
          "severity",
          "trader",
          "market",
          "scores",
          "evidence",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Prefixed ID (rf_...)."
          },
          "suspicion_score": {
            "type": "number",
            "minimum": 60,
            "maximum": 100,
            "description": "Stored score that met the live flag threshold."
          },
          "severity": {
            "type": "string",
            "enum": ["flag"],
            "description": "The live scorer persists one threshold class."
          },
          "trader": {
            "type": "object",
            "required": ["id", "address", "username"],
            "properties": {
              "id": {
                "type": "string"
              },
              "address": {
                "type": "string"
              },
              "username": {
                "type": ["string", "null"]
              }
            }
          },
          "market": {
            "type": "object",
            "required": ["id", "condition_id", "title"],
            "properties": {
              "id": {
                "type": "string"
              },
              "condition_id": {
                "type": "string"
              },
              "title": {
                "type": ["string", "null"],
                "description": "Canonical market question when available."
              }
            }
          },
          "scores": {
            "type": "object",
            "required": ["timing", "edge", "size", "fresh_wallet"],
            "properties": {
              "timing": {
                "type": ["number", "null"],
                "description": "Null because the live scorer does not record this component."
              },
              "edge": {
                "type": ["number", "null"],
                "description": "Null because the live scorer does not record this component."
              },
              "size": {
                "type": ["number", "null"],
                "description": "Numeric evidence.size when recorded; otherwise null."
              },
              "fresh_wallet": {
                "type": ["number", "null"],
                "description": "Numeric evidence.fresh when recorded; otherwise null."
              }
            }
          },
          "evidence": {
            "description": "Stored whale_alerts.suspicion_signals JSON from the scorer."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Stored trade timestamp."
          }
        }
      },
      "ApiErrorBody": {
        "type": "object",
        "required": ["code", "message"],
        "properties": {
          "code": {
            "type": "string",
            "description": "FROZEN: an existing value never changes meaning. request_timeout (408, #16146) was added the way insufficient_scope was: the handler did not answer inside the server's 30-second timeout. Retry-After and retry_at ride on it only for a safe method (GET, HEAD); a timed-out mutation may have completed, so check its state and reuse its Idempotency-Key.",
            "enum": [
              "bad_request",
              "invalid_api_key",
              "subscription_required",
              "forbidden",
              "insufficient_scope",
              "not_found",
              "account_locked",
              "rate_limited",
              "rate_limit_unavailable",
              "internal_error",
              "request_timeout",
              "endpoint_retired"
            ]
          },
          "message": {
            "type": "string"
          },
          "doc_url": {
            "type": "string"
          },
          "param": {
            "type": "string"
          },
          "retry_at": {
            "type": "string",
            "format": "date-time",
            "description": "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."
          },
          "freshness": {
            "$ref": "#/components/schemas/FreshnessFailure"
          },
          "billing_url": {
            "type": "string",
            "format": "uri",
            "description": "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."
          },
          "reason": {
            "type": "string",
            "enum": [
              "cursor_expired",
              "unknown_endpoint",
              "pick_not_released",
              "trader_not_tracked",
              "market_out_of_scope",
              "fill_history_too_large",
              "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"
            ],
            "description": "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. fill_history_too_large (404 not_found, #33245): the wallet and market are tracked, but the position timeline sums every earlier fill into its running totals and this wallet has more than 20,000 fills on the market before the requested page -- stop asking for this pair; neither a retry nor another page 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."
          }
        }
      },
      "FreshnessFailure": {
        "type": "object",
        "required": ["max_age_s", "data_quality_status"],
        "properties": {
          "max_age_s": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "The caller's requested whole-response freshness ceiling in seconds."
          },
          "actual_age_s": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Age in seconds of the oldest stored data_quality.as_of clock, when one is available."
          },
          "as_of": {
            "type": "string",
            "format": "date-time",
            "description": "The oldest stored data-quality clock used to calculate actual_age_s, when one is available."
          },
          "data_quality_status": {
            "type": "string",
            "enum": ["fresh", "stale", "partial", "unknown", "untracked", "unavailable"],
            "description": "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."
          }
        }
      },
      "BatchRateLimitMeta": {
        "type": "object",
        "required": ["basis", "limit", "remaining", "reset"],
        "properties": {
          "basis": {
            "type": "string",
            "const": "batch_items_per_minute"
          },
          "limit": {
            "type": "integer",
            "description": "The batch item budget per minute for the caller's plan: 2500 item units on Pro, 5000 on Max. The same number X-Batch-RateLimit-Limit reports."
          },
          "remaining": {
            "type": "integer"
          },
          "reset": {
            "type": "integer",
            "description": "Unix timestamp when the batch item window resets."
          }
        }
      },
      "BatchResponseMeta": {
        "type": "object",
        "required": [
          "request_id",
          "cached",
          "total_items",
          "successful_items",
          "failed_items",
          "request_cost",
          "rate_limit"
        ],
        "properties": {
          "request_id": {
            "type": "string",
            "description": "Unique request ID (req_ prefix). The same value as the X-Request-Id response header, the request's usage accounting row and its log lines."
          },
          "cached": {
            "type": "boolean"
          },
          "total_items": {
            "type": "integer"
          },
          "successful_items": {
            "type": "integer"
          },
          "failed_items": {
            "type": "integer"
          },
          "request_cost": {
            "type": "integer",
            "description": "Number of batch item units reserved before execution."
          },
          "rate_limit": {
            "$ref": "#/components/schemas/BatchRateLimitMeta"
          }
        }
      },
      "BatchTraderItem": {
        "type": "object",
        "required": ["index", "input", "status"],
        "properties": {
          "index": {
            "type": "integer",
            "description": "Zero-based request index. Duplicate inputs keep separate result rows."
          },
          "input": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": ["ok", "error"]
          },
          "data": {
            "$ref": "#/components/schemas/Trader"
          },
          "error": {
            "$ref": "#/components/schemas/ApiErrorBody"
          }
        }
      },
      "BatchMarketCloseItem": {
        "type": "object",
        "required": ["index", "input", "status"],
        "properties": {
          "index": {
            "type": "integer",
            "description": "Zero-based request index. Duplicate inputs keep separate result rows."
          },
          "input": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": ["ok", "error"]
          },
          "data": {
            "$ref": "#/components/schemas/MarketClose"
          },
          "error": {
            "$ref": "#/components/schemas/ApiErrorBody"
          }
        }
      },
      "BatchMarketFlowItem": {
        "type": "object",
        "required": ["index", "input", "status"],
        "properties": {
          "index": {
            "type": "integer",
            "description": "Zero-based request index. Duplicate inputs keep separate result rows."
          },
          "input": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": ["ok", "error"]
          },
          "data": {
            "$ref": "#/components/schemas/MarketFlow"
          },
          "error": {
            "$ref": "#/components/schemas/ApiErrorBody"
          }
        }
      },
      "BatchGameHoldersItem": {
        "type": "object",
        "required": ["index", "input", "status"],
        "properties": {
          "index": {
            "type": "integer",
            "description": "Zero-based request index. Duplicate inputs keep separate result rows."
          },
          "input": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": ["ok", "error"]
          },
          "data": {
            "$ref": "#/components/schemas/GameHoldersItem"
          },
          "error": {
            "$ref": "#/components/schemas/ApiErrorBody"
          }
        }
      },
      "GameHoldersItem": {
        "type": "object",
        "description": "One market of a game holders batch: GET /api/v1/market/{condition_id}/holders unfiltered and cut to the batch limit.",
        "required": [
          "data",
          "has_more",
          "total",
          "market",
          "scan",
          "totals",
          "computed_at",
          "cached",
          "stale"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "The roster's top holders by current value, at most limit.",
            "items": {
              "$ref": "#/components/schemas/MarketHolder"
            }
          },
          "has_more": {
            "type": "boolean",
            "description": "More graded holders than limit: page them on GET /api/v1/market/{condition_id}/holders."
          },
          "total": {
            "type": "integer",
            "description": "Graded holders in the roster, across every page."
          },
          "market": {
            "$ref": "#/components/schemas/MarketHoldersMarket"
          },
          "scan": {
            "$ref": "#/components/schemas/MarketHoldersScan"
          },
          "totals": {
            "$ref": "#/components/schemas/MarketHoldersTotals"
          },
          "computed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When this roster was computed. A fresh cached roster is at most 60 seconds old; a stale one at most 15 minutes."
          },
          "cached": {
            "type": "boolean",
            "description": "true when the roster came from the cache."
          },
          "stale": {
            "type": "boolean",
            "description": "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."
          }
        }
      },
      "ApiError": {
        "type": "object",
        "required": ["object", "error", "meta"],
        "properties": {
          "object": {
            "type": "string",
            "const": "error"
          },
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": {
              "code": {
                "type": "string",
                "description": "FROZEN: an existing value never changes meaning. request_timeout (408, #16146) was added the way insufficient_scope was: the handler did not answer inside the server's 30-second timeout. Retry-After and retry_at ride on it only for a safe method (GET, HEAD); a timed-out mutation may have completed, so check its state and reuse its Idempotency-Key.",
                "enum": [
                  "bad_request",
                  "invalid_api_key",
                  "subscription_required",
                  "forbidden",
                  "insufficient_scope",
                  "not_found",
                  "account_locked",
                  "rate_limited",
                  "rate_limit_unavailable",
                  "internal_error",
                  "request_timeout",
                  "endpoint_retired"
                ]
              },
              "message": {
                "type": "string"
              },
              "doc_url": {
                "type": "string"
              },
              "param": {
                "type": "string"
              },
              "retry_at": {
                "type": "string",
                "format": "date-time",
                "description": "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."
              },
              "freshness": {
                "$ref": "#/components/schemas/FreshnessFailure"
              },
              "billing_url": {
                "type": "string",
                "format": "uri",
                "description": "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."
              },
              "reason": {
                "type": "string",
                "enum": [
                  "cursor_expired",
                  "unknown_endpoint",
                  "pick_not_released",
                  "trader_not_tracked",
                  "market_out_of_scope",
                  "fill_history_too_large",
                  "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"
                ],
                "description": "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. fill_history_too_large (404 not_found, #33245): the wallet and market are tracked, but the position timeline sums every earlier fill into its running totals and this wallet has more than 20,000 fills on the market before the requested page -- stop asking for this pair; neither a retry nor another page 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."
              }
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        }
      },
      "ReportSnapshot": {
        "type": "object",
        "required": [
          "kind",
          "generated_at",
          "source_range",
          "snapshot",
          "completeness",
          "reconciliation",
          "report"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "enum": ["daily", "weekly", "monthly"]
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "source_range": {
            "$ref": "#/components/schemas/ReportSourceRange"
          },
          "snapshot": {
            "$ref": "#/components/schemas/SnapshotState"
          },
          "completeness": {
            "$ref": "#/components/schemas/SnapshotCompleteness"
          },
          "reconciliation": {
            "$ref": "#/components/schemas/ReportReconciliation"
          },
          "report": {
            "$ref": "#/components/schemas/ReportPayload"
          }
        }
      },
      "ReportSourceRange": {
        "type": "object",
        "required": ["start_date", "end_date", "timezone"],
        "properties": {
          "start_date": {
            "type": "string",
            "format": "date"
          },
          "end_date": {
            "type": "string",
            "format": "date"
          },
          "timezone": {
            "type": "string",
            "const": "UTC"
          }
        }
      },
      "SnapshotState": {
        "type": "object",
        "required": [
          "version",
          "storage",
          "status",
          "generated_at",
          "mutable_until",
          "period_closed",
          "final_after",
          "source_read_started_at"
        ],
        "properties": {
          "version": {
            "type": "integer",
            "format": "int64",
            "description": "Immutable content version for a durable report identity; 0 for an ephemeral explicit weekly from/to range."
          },
          "storage": {
            "type": "string",
            "enum": ["durable", "ephemeral"],
            "description": "durable for canonical daily, ISO-week, and monthly snapshot identities; ephemeral for explicit weekly from/to ranges, which are recomputed within a bounded 31-day window and never persisted."
          },
          "status": {
            "type": "string",
            "enum": ["final", "rolling"],
            "description": "final only for a body whose source read started at or after final_after (the UTC close of the range plus the whale-trade ingestion budget). rolling for a live range and for a closed range still inside that budget: such a body refreshes every five minutes, is rebuilt once after final_after, and is then frozen. Before 2026-09-22 a closed range read final from the calendar alone, even for a body built before the range ended (#16225)."
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "mutable_until": {
            "type": ["string", "null"],
            "format": "date",
            "description": "For a rolling body, the UTC date on which a final body can first be built (the date of final_after); null once final."
          },
          "period_closed": {
            "type": "boolean",
            "description": "Whether the source range has ended on the UTC calendar. Closing is not finality: a closed range is rolling until final_after."
          },
          "final_after": {
            "type": "string",
            "format": "date-time",
            "description": "The instant a source read must start at or after to produce a final body: the range's UTC close plus 7,530 s, the whale-trade ingestion budget (p95 block lag gate plus the projection retry budget)."
          },
          "source_read_started_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When this body's source read started, the clock finality is judged on. null for a body stored before that clock was recorded."
          }
        }
      },
      "SnapshotCompleteness": {
        "type": "object",
        "required": [
          "status",
          "reason",
          "expected_days",
          "covered_days_with_large_trade_activity",
          "covered_days_with_whale_activity"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["complete", "partial", "empty"],
            "description": "complete only on a final body (snapshot.status final). partial for a live range and for a closed range whose body was read before final_after; reason says which. empty when the range has no whale activity."
          },
          "reason": {
            "type": "string"
          },
          "expected_days": {
            "type": "integer"
          },
          "covered_days_with_large_trade_activity": {
            "description": "Canonical key since #16304; covered_days_with_whale_activity is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
            "type": "integer"
          },
          "covered_days_with_whale_activity": {
            "deprecated": true,
            "description": "Deprecated spelling of covered_days_with_large_trade_activity, emitted beside it with the same value. Sunset 2027-02-01 (#29352): removed from V1 on that date; read covered_days_with_large_trade_activity.",
            "type": "integer"
          }
        }
      },
      "ReportReconciliation": {
        "type": "object",
        "required": ["volume_kind", "whale_volume_source", "notes"],
        "properties": {
          "volume_kind": {
            "type": "string",
            "const": "local_whale_activity_volume"
          },
          "whale_volume_source": {
            "type": "string",
            "description": "Where the whale volume in this report is read from: the column name `whale_alerts.usdc_notional_num`, followed in parentheses by the reconciliation note the server attaches to it. The server has always sent the note with the name, so this is not a bare constant; match on the prefix, not the whole string."
          },
          "notes": {
            "type": "string"
          }
        }
      },
      "ReportPayload": {
        "type": "object",
        "required": [
          "total_large_trades",
          "total_whale_trades",
          "total_large_trade_volume",
          "total_whale_volume",
          "biggest_trade_size",
          "active_traders",
          "top_large_trades",
          "top_whale_trades",
          "categories",
          "grade_distribution",
          "market_scope"
        ],
        "properties": {
          "total_large_trades": {
            "description": "Canonical key since #16304; total_whale_trades is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
            "type": ["integer", "null"]
          },
          "total_whale_trades": {
            "type": ["integer", "null"]
          },
          "total_large_trade_volume": {
            "description": "Canonical key since #16304; total_whale_volume is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
            "type": ["number", "null"]
          },
          "total_whale_volume": {
            "type": ["number", "null"]
          },
          "biggest_trade_size": {
            "type": ["number", "null"]
          },
          "active_traders": {
            "type": ["integer", "null"]
          },
          "top_large_trades": {
            "description": "Canonical key since #16304; top_whale_trades is its deprecated spelling, emitted beside it with the same value until its sunset on 2027-02-01 (#29352).",
            "type": ["array", "null"],
            "items": {
              "type": "object",
              "required": [
                "outcome",
                "side",
                "title",
                "size",
                "price",
                "token_id",
                "id",
                "trade_time",
                "market_category",
                "platform",
                "name",
                "pseudonym",
                "trader_grade"
              ],
              "properties": {
                "outcome": {
                  "type": ["string", "null"],
                  "description": "Provider outcome label for the traded side."
                },
                "side": {
                  "type": ["string", "null"],
                  "description": "Trade direction (BUY or SELL), not the outcome side."
                },
                "title": {
                  "type": ["string", "null"],
                  "description": "Market title."
                },
                "size": {
                  "type": ["number", "null"],
                  "description": "Trade size in USD."
                },
                "price": {
                  "type": ["number", "null"],
                  "description": "Trade price in provider [0, 1] units."
                },
                "token_id": {
                  "type": ["string", "null"],
                  "description": "The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the traded outcome; null when unavailable (e.g. unsynced markets)."
                },
                "id": {
                  "type": ["integer", "null"],
                  "format": "int64",
                  "description": "Whale trade id."
                },
                "trade_time": {
                  "type": ["string", "null"],
                  "format": "date-time",
                  "description": "Trade timestamp (UTC)."
                },
                "market_category": {
                  "type": ["string", "null"],
                  "description": "Provider market category."
                },
                "platform": {
                  "type": ["string", "null"],
                  "enum": ["polymarket", null],
                  "description": "Always polymarket, or null when the row carries no stored value."
                },
                "name": {
                  "type": ["string", "null"],
                  "description": "Trader display name, when known."
                },
                "pseudonym": {
                  "type": ["string", "null"],
                  "description": "Trader pseudonym, when no display name is known."
                },
                "trader_grade": {
                  "type": ["string", "null"],
                  "description": "Trader grade (S-F) at snapshot time.",
                  "enum": ["S", "A", "B", "C", "D", "F", null]
                }
              }
            }
          },
          "top_whale_trades": {
            "type": ["array", "null"],
            "items": {
              "type": "object",
              "required": [
                "outcome",
                "side",
                "title",
                "size",
                "price",
                "token_id",
                "id",
                "trade_time",
                "market_category",
                "platform",
                "name",
                "pseudonym",
                "trader_grade"
              ],
              "properties": {
                "outcome": {
                  "type": ["string", "null"],
                  "description": "Provider outcome label for the traded side."
                },
                "side": {
                  "type": ["string", "null"],
                  "description": "Trade direction (BUY or SELL), not the outcome side."
                },
                "title": {
                  "type": ["string", "null"],
                  "description": "Market title."
                },
                "size": {
                  "type": ["number", "null"],
                  "description": "Trade size in USD."
                },
                "price": {
                  "type": ["number", "null"],
                  "description": "Trade price in provider [0, 1] units."
                },
                "token_id": {
                  "type": ["string", "null"],
                  "description": "The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the traded outcome; null when unavailable (e.g. unsynced markets)."
                },
                "id": {
                  "type": ["integer", "null"],
                  "format": "int64",
                  "description": "Whale trade id."
                },
                "trade_time": {
                  "type": ["string", "null"],
                  "format": "date-time",
                  "description": "Trade timestamp (UTC)."
                },
                "market_category": {
                  "type": ["string", "null"],
                  "description": "Provider market category."
                },
                "platform": {
                  "type": ["string", "null"],
                  "enum": ["polymarket", null],
                  "description": "Always polymarket, or null when the row carries no stored value."
                },
                "name": {
                  "type": ["string", "null"],
                  "description": "Trader display name, when known."
                },
                "pseudonym": {
                  "type": ["string", "null"],
                  "description": "Trader pseudonym, when no display name is known."
                },
                "trader_grade": {
                  "type": ["string", "null"],
                  "description": "Trader grade (S-F) at snapshot time.",
                  "enum": ["S", "A", "B", "C", "D", "F", null]
                }
              }
            }
          },
          "categories": {
            "type": ["array", "null"],
            "items": {
              "type": "object",
              "properties": {
                "category": {
                  "type": ["string", "null"]
                },
                "large_trade_count": {
                  "type": ["integer", "null"]
                },
                "whale_trade_count": {
                  "type": ["integer", "null"]
                },
                "category_volume": {
                  "type": ["number", "null"]
                }
              },
              "required": ["category", "large_trade_count", "whale_trade_count", "category_volume"]
            }
          },
          "grade_distribution": {
            "type": ["array", "null"],
            "items": {
              "type": "object",
              "properties": {
                "grade": {
                  "type": ["string", "null"],
                  "enum": ["S", "A", "B", "C", "D", "F", null]
                },
                "count": {
                  "type": ["integer", "null"]
                }
              },
              "required": ["grade", "count"]
            },
            "description": "Counts of current grades for distinct Polymarket traders with at least one whale alert in the report's source date range. The grade is the current projection at snapshot materialization time, not a historical grade at trade time. Traders without a current ranking projection are omitted; a null grade entry means the active trader's current grade is unavailable."
          },
          "market_scope": {
            "type": "string",
            "enum": ["all_markets", "sports_and_esports"],
            "description": "Which markets the report counts. sports_and_esports for a period that ends on or after 2026-10-21: totals, categories, top trades and the grade cohort cover sports and esports markets only. all_markets for an earlier period, whose stored report keeps every Polymarket market it published."
          }
        }
      },
      "TraderExportSnapshot": {
        "type": "object",
        "required": [
          "address",
          "product_scope",
          "generated_at",
          "source_range",
          "completeness",
          "reconciliation",
          "counts",
          "large_export_policy"
        ],
        "properties": {
          "address": {
            "type": "string"
          },
          "product_scope": {
            "type": "string",
            "const": "sports_esports_v1",
            "description": "The markets the export file's trades and markets sections hold: sports and esports markets only. counts.exported_markets, counts.estimated_trade_rows, counts.estimated_size_mb, reconciliation.exported_market_cost_basis and source_range.latest_trade_at and latest_market_activity_at describe those markets, and reconciliation.exported_activity_volume is the cash the wallet traded in sports and esports markets. source_range.first_pnl_date, last_pnl_date and pnl_series_status and counts.pnl_days describe the file's pnl section, the wallet's sports and esports realized P&L by day. completeness.sync_coverage is the wallet's stored markets (its sports and esports markets since 2026-10-27, #29366) plus the markets of other categories whose rows were deleted and counted (position_summary.markets_pruned on the context) and those first traded since 2026-10-26, which are not stored and are counted as the wallet syncs (position_summary.markets_unstored, #30165) and its combo markets, which Polymarket counts and no position read lists (position_summary.markets_combo, #30218), over Polymarket's count of every market it traded: both sides count every category, so a fully synced wallet reads 1.0 and complete. A wallet with nothing stored and no pnl day is empty whatever its coverage."
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "source_range": {
            "$ref": "#/components/schemas/ExportSourceRange"
          },
          "completeness": {
            "$ref": "#/components/schemas/ExportCompleteness"
          },
          "reconciliation": {
            "$ref": "#/components/schemas/ExportVolumeReconciliation"
          },
          "counts": {
            "$ref": "#/components/schemas/ExportCounts"
          },
          "large_export_policy": {
            "$ref": "#/components/schemas/LargeExportPolicy"
          }
        }
      },
      "ExportSourceRange": {
        "type": "object",
        "required": [
          "first_pnl_date",
          "last_pnl_date",
          "pnl_series_status",
          "latest_trade_at",
          "latest_market_activity_at"
        ],
        "properties": {
          "first_pnl_date": {
            "type": ["string", "null"],
            "format": "date",
            "description": "The first UTC day in the export file's pnl section, the wallet's sports and esports realized P&L by day: the file's export_metadata.pnl_date_from. Null when that section has no day, including while pnl_series_status is pending."
          },
          "last_pnl_date": {
            "type": ["string", "null"],
            "format": "date",
            "description": "The last UTC day in the export file's pnl section: the file's export_metadata.pnl_date_to. Null when that section has no day."
          },
          "pnl_series_status": {
            "type": "string",
            "enum": ["ready", "pending"],
            "description": "Whether the export file's pnl section holds the wallet's sports and esports day series, the file's export_metadata.pnl_series_status. pending means 0xinsider has not computed the series yet: the dates are null and counts.pnl_days is 0, which then never means the wallet has no day. A wallet that traded no sports or esports market is ready with null dates and counts.pnl_days 0: it never gets a series, and with nothing stored completeness.status is empty (since 2026-10-29, #30620, #30657)."
          },
          "latest_trade_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "The latest trade in the wallet's sports and esports markets. Null when it has none."
          },
          "latest_market_activity_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Same instant as latest_trade_at: the latest activity of the markets the export holds."
          }
        }
      },
      "ExportCompleteness": {
        "type": "object",
        "required": ["status", "reason", "sync_coverage"],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["complete", "partial", "empty"]
          },
          "reason": {
            "type": "string"
          },
          "sync_coverage": {
            "type": "number",
            "minimum": 0
          }
        }
      },
      "ExportVolumeReconciliation": {
        "type": "object",
        "required": [
          "provider_lifetime_volume",
          "exported_activity_volume",
          "exported_market_cost_basis",
          "provider_activity_volume_gap",
          "activity_volume_coverage"
        ],
        "properties": {
          "provider_lifetime_volume": {
            "deprecated": true,
            "type": ["number", "null"],
            "description": "Deprecated (#30499): always null since 2026-10-29. It held Polymarket's volume across every market of the wallet, which reconciles nothing against the sports and esports exported_activity_volume; the key stays so existing V1 clients keep parsing. Read exported_activity_volume for the wallet's sports and esports volume."
          },
          "exported_activity_volume": {
            "type": ["number", "null"],
            "description": "Volume in USD, buys and sells, in sports and esports markets, each fill's size times its price with fees excluded, summed over the wallet's stored daily volume rows (from the fills 0xinsider stores for the wallet): the export file's summary.volume_reconciliation.exported_activity_volume, not the sum of its pnl[].total_volume, which is null on a day the trade rollups do not cover. Never Polymarket's share count. Null when any of those rows has no volume: a sum over the other days would be a partial subtotal."
          },
          "exported_market_cost_basis": {
            "type": "number",
            "description": "Cost basis in USD summed over the wallet's sports and esports markets, the markets section of the export."
          },
          "provider_activity_volume_gap": {
            "type": ["number", "null"],
            "description": "Always null. provider_lifetime_volume covered every market and exported_activity_volume sports and esports markets only, so their difference measured nothing; the field stays so existing clients keep parsing the object."
          },
          "activity_volume_coverage": {
            "type": ["number", "null"],
            "description": "Always null, for the same reason as provider_activity_volume_gap."
          }
        }
      },
      "ExportCounts": {
        "type": "object",
        "required": ["pnl_days", "exported_markets", "estimated_trade_rows", "estimated_size_mb"],
        "properties": {
          "pnl_days": {
            "type": "integer",
            "description": "The days in the export file's pnl section, the wallet's sports and esports realized P&L by UTC day: the file's export_metadata.pnl_rows, at most its earliest 3650 days. 0 while source_range.pnl_series_status is pending, and 0 with it ready for a wallet that traded no sports or esports market."
          },
          "exported_markets": {
            "type": "integer",
            "description": "The wallet's sports and esports markets: the rows of the export's markets section, before its 50,000-row cap."
          },
          "estimated_trade_rows": {
            "type": "integer",
            "description": "Estimated trades in the wallet's sports and esports markets: the summed trade counts of those markets. The file counts its own rows in generation.source_watermarks.trades.rows."
          },
          "estimated_size_mb": {
            "type": "number",
            "description": "Estimated file size from estimated_trade_rows and exported_markets."
          }
        }
      },
      "TraderExportJob": {
        "type": "object",
        "required": ["object", "data", "meta"],
        "properties": {
          "object": {
            "type": "string",
            "const": "trader_export_job"
          },
          "data": {
            "type": "object",
            "required": [
              "job_id",
              "status",
              "format",
              "total_trades",
              "processed_trades",
              "file_size",
              "error",
              "terminal",
              "next_action",
              "created_at",
              "started_at",
              "ready_at",
              "failed_at",
              "expires_at",
              "expired_at",
              "data_as_of",
              "cancel_requested_at",
              "cancelled_at",
              "attempt",
              "max_attempts"
            ],
            "properties": {
              "job_id": {
                "type": "integer",
                "format": "int64"
              },
              "status": {
                "type": "string",
                "enum": [
                  "queued",
                  "running",
                  "ready",
                  "failed",
                  "reconcile_required",
                  "expired",
                  "cancel_requested",
                  "cancelled"
                ],
                "description": "queued: waiting for a worker. A running job reads queued again, with error saying why, when its worker restarts for a deploy (the next worker claims it within seconds) or stops without handing it back (requeued within a minute of its 30-minute lease lapsing); it starts again from the beginning. running: the worker is streaming rows. reconcile_required: the upload finished but the storage completion answer was lost; the reconciler reads the object back within a minute, retries a failed readback an hour later, and moves the job to ready or failed, and expires_at bounds the wait. ready: downloadable until expires_at. failed: terminal; error says why; submit a new export. expired: the retention window passed; the file is retired, the download route answers 410, submit a new export. cancel_requested: the owner cancelled a running job (POST /api/v1/trader/{address}/export/cancel); the worker stops at its next safe point and the job reads cancelled. cancelled: terminal; the owner cancelled the job and no file was published; submit a new export. A job that has not reached ready by expires_at reads failed with error 'export expired before completion'. failed, cancelled and expired rows stay readable for 48 hours, then the job answers 404."
              },
              "format": {
                "type": "string",
                "enum": ["json", "ndjson", "csv"]
              },
              "total_trades": {
                "type": ["integer", "null"],
                "format": "int64",
                "description": "Trade rows the file holds: trades in the wallet's sports and esports markets, counted in the file's own read snapshot. Null until the worker has read the snapshot (queued, and early in running); a job accepted before 2026-10-22 can carry the earlier all-markets estimate until its file is read."
              },
              "processed_trades": {
                "type": ["integer", "null"],
                "format": "int64",
                "description": "Trade rows written so far; equals total_trades once the file is read."
              },
              "file_size": {
                "type": ["integer", "null"],
                "format": "int64"
              },
              "error": {
                "type": ["string", "null"]
              },
              "terminal": {
                "type": "boolean",
                "description": "True when status never changes again (ready, failed, expired, cancelled). Stop polling."
              },
              "next_action": {
                "type": "string",
                "enum": ["poll", "download", "resubmit"],
                "description": "What to do next: poll the status route after poll_after_s, follow the download route, or submit a new export. Published beside status so a status value added later does not strand a client."
              },
              "poll_after_s": {
                "type": "integer",
                "description": "Seconds to wait before polling again. Absent when terminal. 5 while queued, running or cancel_requested; 300 while reconcile_required, the cadence that state can change at."
              },
              "created_at": {
                "type": "string",
                "format": "date-time"
              },
              "started_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "When the worker last claimed the job; null while queued."
              },
              "ready_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "When the file became downloadable. null before ready, and on jobs finalized before this field existed."
              },
              "failed_at": {
                "type": ["string", "null"],
                "format": "date-time"
              },
              "expires_at": {
                "type": "string",
                "format": "date-time",
                "description": "The retention window: 24 hours from submit. A ready file downloads until this instant; a job that has not reached ready by it fails. A reused job (200 on submit) keeps its original window."
              },
              "expired_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "When the job became expired; null until then."
              },
              "data_as_of": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "What the file is a snapshot of: the trader's served-data clock (the latest position refresh, else the last completed sync) when the file was written; the same value as export_metadata.data_as_of inside the file. null until the file is written, or when the trader had neither. Read this, not ready_at, to decide whether a reused job is fresh enough; submit with fresh=true for a newer snapshot."
              },
              "cancel_requested_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "When the owner asked to cancel the job; null otherwise. Set on every cancelled job, including one cancelled while queued. While status is cancel_requested this is the instant the worker was asked to stop."
              },
              "cancelled_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "When the job reached cancelled; null until then."
              },
              "attempt": {
                "type": "integer",
                "description": "Worker claims so far. A claim handed back when its worker restarts for a deploy is not counted, so attempt steps back by one when the job reads queued again for that reason."
              },
              "max_attempts": {
                "type": "integer",
                "description": "The job fails when attempt reaches this."
              },
              "artifact": {
                "type": "object",
                "description": "Present only while status is ready: the stored object's identity, so a client can check the download it receives.",
                "required": [
                  "artifact_id",
                  "etag",
                  "compressed_size_bytes",
                  "content_type",
                  "content_encoding",
                  "manifest"
                ],
                "properties": {
                  "artifact_id": {
                    "type": "string",
                    "description": "Stable identity for this completed export artifact; unchanged when a temporary download URL is renewed."
                  },
                  "etag": {
                    "type": ["string", "null"],
                    "description": "The storage ETag of the object."
                  },
                  "compressed_size_bytes": {
                    "type": ["integer", "null"],
                    "format": "int64",
                    "description": "Bytes on the wire (gzip); file_size is the decompressed size."
                  },
                  "content_type": {
                    "type": "string",
                    "enum": ["application/json", "application/x-ndjson", "text/csv"]
                  },
                  "content_encoding": {
                    "type": "string",
                    "const": "gzip"
                  },
                  "manifest": {
                    "oneOf": [
                      {
                        "$ref": "#/components/schemas/TraderExportArtifactManifest"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Immutable manifest for artifacts generated with manifest support; null on historical artifacts written before this contract."
                  }
                }
              }
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        }
      },
      "TraderExportArtifactManifest": {
        "type": "object",
        "required": [
          "manifest_version",
          "format",
          "schema_version",
          "coverage",
          "generation",
          "row_count",
          "content_size_bytes",
          "content_sha256",
          "compressed_size_bytes",
          "compressed_sha256"
        ],
        "properties": {
          "manifest_version": {
            "type": "string",
            "description": "Version of the artifact manifest contract."
          },
          "format": {
            "type": "string",
            "enum": ["json", "ndjson", "csv"],
            "description": "Serialization used for the decompressed content."
          },
          "schema_version": {
            "type": "string",
            "enum": ["trader-export-json-v1", "trader-export-ndjson-v1", "trader-export-csv-v1"],
            "description": "Stable schema identifier for the selected serialization."
          },
          "coverage": {
            "type": "string",
            "enum": ["full_envelope_and_trades", "trades_only"],
            "description": "Sections represented by the artifact. JSON and NDJSON carry the full envelope and trades; CSV carries trade rows only."
          },
          "generation": {
            "$ref": "#/components/schemas/TraderExportGeneration",
            "x-narrowed": true
          },
          "row_count": {
            "type": "integer",
            "format": "int64",
            "description": "Number of trade rows written."
          },
          "content_size_bytes": {
            "type": "integer",
            "format": "int64",
            "description": "Exact byte count of the decompressed content stream clients receive."
          },
          "content_sha256": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "Lowercase SHA-256 of the decompressed content bytes."
          },
          "compressed_size_bytes": {
            "type": "integer",
            "format": "int64",
            "description": "Exact byte count of the gzip-compressed bytes stored by the object provider."
          },
          "compressed_sha256": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "Lowercase SHA-256 of the stored gzip bytes; the multipart ETag is not used as this checksum."
          }
        }
      },
      "TraderExportGeneration": {
        "type": "object",
        "required": ["id", "selected_at", "consistency", "source_watermarks"],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Opaque generation identity selected for the coherent read snapshot."
          },
          "selected_at": {
            "type": "string",
            "format": "date-time"
          },
          "consistency": {
            "type": "string",
            "const": "repeatable_read"
          },
          "source_watermarks": {
            "$ref": "#/components/schemas/TraderExportSourceWatermarks"
          },
          "product_scope": {
            "type": "string",
            "const": "sports_esports_v1",
            "description": "The markets the file's trades and markets sections hold: sports and esports markets only (export_metadata.scope_note in a JSON or NDJSON file names the sections that still cover every market). Absent on a file written before 2026-10-22, which holds every market; a submit never reuses such a file."
          }
        }
      },
      "TraderExportSourceWatermarks": {
        "type": "object",
        "required": ["positions", "pnl", "categories", "trades"],
        "properties": {
          "positions": {
            "$ref": "#/components/schemas/TraderExportPositionWatermark"
          },
          "pnl": {
            "$ref": "#/components/schemas/TraderExportPnlWatermark"
          },
          "categories": {
            "$ref": "#/components/schemas/TraderExportCategoryWatermark"
          },
          "trades": {
            "$ref": "#/components/schemas/TraderExportTradeWatermark"
          }
        }
      },
      "TraderExportPositionWatermark": {
        "type": "object",
        "required": ["source", "coverage", "generation", "data_as_of"],
        "properties": {
          "source": {
            "type": "string"
          },
          "coverage": {
            "type": "string"
          },
          "generation": {
            "type": ["integer", "null"],
            "format": "int64"
          },
          "data_as_of": {
            "type": ["string", "null"],
            "format": "date-time"
          }
        }
      },
      "TraderExportPnlWatermark": {
        "type": "object",
        "required": ["source", "coverage", "revision", "observed_at"],
        "properties": {
          "source": {
            "type": "string"
          },
          "coverage": {
            "type": "string"
          },
          "revision": {
            "type": ["integer", "null"],
            "format": "int64"
          },
          "observed_at": {
            "type": ["string", "null"],
            "format": "date-time"
          }
        }
      },
      "TraderExportCategoryWatermark": {
        "type": "object",
        "required": ["source", "coverage", "publication_fence", "data_as_of"],
        "properties": {
          "source": {
            "type": "string"
          },
          "coverage": {
            "type": "string"
          },
          "publication_fence": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "data_as_of": {
            "type": ["string", "null"],
            "format": "date-time"
          }
        }
      },
      "TraderExportTradeWatermark": {
        "type": "object",
        "required": ["source", "coverage", "rows", "first_activity_date"],
        "properties": {
          "source": {
            "type": "string"
          },
          "coverage": {
            "type": "string",
            "description": "sports_esports_rows: the file holds every stored trade in the wallet's sports and esports markets. all_matching_rows on a file written before 2026-10-22, which holds every market's trades."
          },
          "rows": {
            "type": "integer",
            "format": "int64",
            "description": "Trade rows the file holds, counted in the same read snapshot as the rows."
          },
          "first_activity_date": {
            "type": ["string", "null"],
            "format": "date"
          }
        }
      },
      "LargeExportPolicy": {
        "type": "object",
        "required": [
          "mode",
          "current_internal_route",
          "v1_async",
          "direct_streaming",
          "async_job",
          "rate_limit"
        ],
        "properties": {
          "mode": {
            "type": "string",
            "const": "v1_async_export"
          },
          "current_internal_route": {
            "type": "string"
          },
          "v1_async": {
            "type": "object",
            "description": "Programmatic API-key-gated export routes (submit/status/download/cancel) and supported formats (json, ndjson, csv).",
            "required": [
              "submit_route",
              "status_route",
              "download_route",
              "cancel_route",
              "formats",
              "status_values",
              "retention"
            ],
            "properties": {
              "submit_route": {
                "type": "string",
                "description": "POST route template to submit an export job. fresh=true asks for a snapshot read after the submit instead of reusing a finished one."
              },
              "status_route": {
                "type": "string",
                "description": "GET route template to poll job status."
              },
              "download_route": {
                "type": "string",
                "description": "GET route template that 302-redirects to the file."
              },
              "cancel_route": {
                "type": "string",
                "description": "POST route template to cancel a queued or running job."
              },
              "formats": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": ["json", "ndjson", "csv"]
                },
                "description": "Supported ?format= values."
              },
              "status_values": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "queued",
                    "running",
                    "ready",
                    "failed",
                    "reconcile_required",
                    "expired",
                    "cancel_requested",
                    "cancelled"
                  ]
                },
                "description": "Possible job status values."
              },
              "retention": {
                "type": "string",
                "description": "How long a finished export is retained before expiry."
              }
            }
          },
          "direct_streaming": {
            "type": "object",
            "properties": {
              "available_when": {
                "type": "string"
              },
              "backpressure": {
                "type": "string"
              },
              "chunk_size_rows": {
                "type": "integer"
              }
            },
            "required": ["available_when", "backpressure", "chunk_size_rows"]
          },
          "async_job": {
            "type": "object",
            "properties": {
              "available_when": {
                "type": "string"
              },
              "status_values": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "retention": {
                "type": "string"
              }
            },
            "required": ["available_when", "status_values", "retention"]
          },
          "rate_limit": {
            "type": "object",
            "properties": {
              "daily_cap_per_user": {
                "type": "integer"
              },
              "per_address_hourly_cap": {
                "type": "integer"
              }
            },
            "required": ["daily_cap_per_user", "per_address_hourly_cap"]
          }
        }
      },
      "Usage": {
        "type": "object",
        "required": ["object", "data", "meta"],
        "properties": {
          "object": {
            "type": "string",
            "const": "usage"
          },
          "data": {
            "type": "object",
            "required": ["rate_limit", "daily_usage", "monthly_quota"],
            "properties": {
              "rate_limit": {
                "type": "object",
                "required": ["used", "limit", "remaining", "reset_at", "window_seconds"],
                "properties": {
                  "used": {
                    "type": "integer",
                    "example": 7
                  },
                  "limit": {
                    "type": "integer",
                    "description": "The per-minute window's limit for the caller's plan: 100 requests on Pro, 200 on Max. The same number RateLimit-Limit reports on a counted request.",
                    "example": 100
                  },
                  "remaining": {
                    "type": "integer",
                    "example": 93
                  },
                  "reset_at": {
                    "type": "integer",
                    "example": 1710772860
                  },
                  "window_seconds": {
                    "type": "integer",
                    "example": 60
                  }
                }
              },
              "daily_usage": {
                "type": "object",
                "required": ["used", "limit", "remaining", "reset_at", "window_seconds"],
                "properties": {
                  "used": {
                    "type": "integer",
                    "example": 42
                  },
                  "limit": {
                    "type": ["integer", "null"],
                    "example": null
                  },
                  "remaining": {
                    "type": ["integer", "null"],
                    "example": null
                  },
                  "reset_at": {
                    "type": "integer",
                    "example": 1710806400
                  },
                  "window_seconds": {
                    "type": "integer",
                    "example": 86400
                  }
                },
                "description": "UTC-day usage count. Current V1 has no daily hard cap, so limit and remaining are null rather than synthesized."
              },
              "monthly_quota": {
                "type": ["object", "null"],
                "required": [
                  "used",
                  "limit",
                  "remaining",
                  "reset_at",
                  "enforced_from",
                  "binding",
                  "pay_as_you_go",
                  "ceiling",
                  "unavailable_reason"
                ],
                "properties": {
                  "used": {
                    "type": "integer",
                    "example": 41230,
                    "description": "Admitted requests so far this UTC calendar month."
                  },
                  "limit": {
                    "type": "integer",
                    "example": 500000,
                    "description": "Requests the account's plan includes per UTC calendar month: 500,000 for Pro, 2,000,000 for Max."
                  },
                  "remaining": {
                    "type": "integer",
                    "example": 458770
                  },
                  "reset_at": {
                    "type": "integer",
                    "example": 1793491200,
                    "description": "Unix seconds: the first instant of the next UTC calendar month."
                  },
                  "enforced_from": {
                    "type": "integer",
                    "example": 1790812800,
                    "description": "Unix seconds: from when request limit + 1 is refused for an account the quota binds."
                  },
                  "binding": {
                    "type": "boolean",
                    "example": false,
                    "description": "Whether requests over this account's ceiling are refused right now: false before enforced_from and for an admin account."
                  },
                  "pay_as_you_go": {
                    "type": "boolean",
                    "example": false,
                    "description": "Pay as you go is on: requests over the quota keep answering and bill on a monthly invoice, up to ceiling."
                  },
                  "ceiling": {
                    "type": ["integer", "null"],
                    "example": 500000,
                    "description": "The most requests this account is admitted in a UTC calendar month once enforcement has begun: limit, or four times limit with pay as you go on (2,000,000 for Pro). null for an admin account, which no number stops. Additive since 2026-09-22."
                  },
                  "unavailable_reason": {
                    "type": ["string", "null"],
                    "enum": ["usage_price_reconciliation_required", null],
                    "example": null,
                    "description": "Why pay as you go is unavailable, or null. usage_price_reconciliation_required: the account's usage subscription carries a historical price whose included requests differ from its plan's, so pay as you go stays off (pay_as_you_go false) until billing reconciles it. Always sent since 2026-10-17."
                  }
                },
                "description": "The monthly request quota (#16111): where the account stands against the requests the current Pro or Max plan includes per UTC calendar month. Reading it here spends nothing. null only when the month's count could not be read for this response."
              }
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        }
      },
      "LargePosition": {
        "type": "object",
        "required": [
          "id",
          "platform",
          "is_two_sided",
          "holdings",
          "share_count",
          "token_id",
          "event_leg_count",
          "first_seen_at",
          "last_updated_at",
          "trader",
          "market"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Composite prefixed ID `pos_<wallet>:<condition_id>:<outcome_index>`."
          },
          "platform": {
            "type": "string",
            "enum": ["polymarket"],
            "description": "Provider discriminator. Always polymarket."
          },
          "total_size_usd": {
            "type": "number",
            "description": "Provider currentValue in USD for the outcome named by outcome_label / token_id, and for that outcome only. An absent key means the provider supplied no value for this leg, not a zero position. combined_value_usd carries the wallet's whole-market total."
          },
          "position_unrealized_pnl": {
            "type": "number",
            "description": "Provider unrealized mark-to-market P&L (Polymarket cashPnl) for that same one outcome. An absent key means unavailable, not break-even."
          },
          "combined_value_usd": {
            "type": "number",
            "description": "The wallet's currentValue across every outcome it holds in this market. Equals total_size_usd unless is_two_sided is true, and is the value the feed ranked this row by."
          },
          "combined_unrealized_pnl": {
            "type": "number",
            "description": "The wallet's unrealized P&L across every outcome it holds in this market. Equals position_unrealized_pnl unless is_two_sided is true."
          },
          "is_two_sided": {
            "type": "boolean",
            "description": "Whether the wallet holds shares on both outcomes of this market."
          },
          "holdings": {
            "type": "array",
            "description": "Every outcome the wallet holds, primary first. holdings[0] restates the top-level per-outcome fields; a further entry is a leg those fields do not describe. No amount here is a share-proportional slice of a both-sides total.",
            "items": {
              "type": "object",
              "required": ["outcome_index", "token_id", "share_count"],
              "properties": {
                "outcome_index": {
                  "type": "integer",
                  "description": "0 = Yes, 1 = No."
                },
                "outcome_label": {
                  "type": "string",
                  "description": "The market's label for this outcome."
                },
                "token_id": {
                  "type": ["string", "null"],
                  "description": "Polymarket CLOB token id for this outcome; null for an unsynced market."
                },
                "share_count": {
                  "type": "number",
                  "description": "Shares held on this outcome."
                },
                "avg_entry_price": {
                  "type": "number",
                  "description": "Provider average entry price for this outcome."
                },
                "current_price": {
                  "type": "number",
                  "description": "Provider mark price for this outcome."
                },
                "value_usd": {
                  "type": "number",
                  "description": "Provider currentValue for this outcome. An absent key means unavailable, not zero."
                },
                "unrealized_pnl": {
                  "type": "number",
                  "description": "Provider unrealized P&L for this outcome. An absent key means unavailable, not break-even."
                }
              }
            }
          },
          "share_count": {
            "type": "number",
            "description": "Live share count for this position."
          },
          "avg_entry_price": {
            "type": "number",
            "description": "Volume-weighted entry price."
          },
          "current_price": {
            "type": "number",
            "description": "Latest provider mark price for the position's token."
          },
          "outcome_label": {
            "type": "string",
            "description": "Backend-resolved outcome label (provider outcome, else Yes/No from the binary index)."
          },
          "token_id": {
            "type": ["string", "null"],
            "description": "The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets)."
          },
          "event_leg_count": {
            "type": "integer",
            "description": "Legs collapsed into this representative row for one (wallet, event, outcome side) group. 1 means standalone."
          },
          "event_total_value_usd": {
            "type": "number",
            "description": "Sum of the collapsed sibling legs' own holding values for this (wallet, event) group; equals total_size_usd when event_leg_count = 1, and omitted when any member's value is unknown."
          },
          "first_seen_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "trader": {
            "type": "object",
            "required": ["id", "address"],
            "properties": {
              "id": {
                "type": "string",
                "description": "Prefixed ID (`trd_...`)."
              },
              "address": {
                "type": "string"
              },
              "username": {
                "type": "string"
              },
              "grade": {
                "type": "string",
                "enum": ["S", "A", "B", "C", "D", "F"]
              },
              "win_rate": {
                "type": "number",
                "description": "Sports and esports win rate as a ratio from 0 to 1 (0.62 means 62%): wins over the decided sports and esports markets on the wallet's record, the same figure as pnl.in_scope.win_rate on GET /api/v1/trader/{address}. Since 2026-10-27 it no longer counts other markets (#29953). Absent when the wallet has no record or no decided market."
              },
              "pnl": {
                "type": "number",
                "deprecated": true,
                "x-never-sent": true,
                "description": "Deprecated since 2026-10-27 and never sent. It was Polymarket's net total P&L over every Polymarket market of the wallet, and wallet figures cover sports and esports markets only (#29953). Read trader.in_scope_realized_pnl."
              },
              "in_scope_realized_pnl": {
                "type": "number",
                "description": "The wallet's realized P&L in USD on sports and esports markets, the figure the 0xinsider profile shows: the record behind pnl.in_scope.realized_pnl on GET /api/v1/trader/{address}, to cents. Distinct from this position's position_unrealized_pnl. For a graded wallet it is read from the latest grading pass, so it can trail that figure until the next pass. Omitted until 0xinsider has computed the wallet's record (#29953)."
              },
              "markets_traded": {
                "type": "integer",
                "description": "Sports and esports markets on the wallet's record, pnl.in_scope.markets on GET /api/v1/trader/{address}. Since 2026-10-27 it no longer counts other markets (#29953). Absent when the wallet has no record."
              }
            }
          },
          "market": {
            "type": "object",
            "required": ["id", "condition_id"],
            "properties": {
              "id": {
                "type": "string",
                "description": "Prefixed ID (`mkt_...`)."
              },
              "condition_id": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "slug": {
                "type": "string"
              },
              "event_slug": {
                "type": "string"
              },
              "category": {
                "type": "string"
              }
            }
          }
        }
      },
      "TrendingWallet": {
        "type": "object",
        "required": [
          "id",
          "address",
          "rank",
          "platform",
          "trending_pnl_usd",
          "window_markets_traded",
          "window_trade_days",
          "daily_pnl_series",
          "daily_pnl_series_status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Prefixed trader ID (`trd_...`)."
          },
          "address": {
            "type": "string"
          },
          "rank": {
            "type": "integer",
            "description": "1-based rank within the full ranked set (stable across pages)."
          },
          "username": {
            "type": "string"
          },
          "profile_image_url": {
            "type": "string",
            "description": "Official Polymarket avatar URL (profileImage)."
          },
          "platform": {
            "type": "string",
            "enum": ["polymarket"],
            "description": "Real provider platform; surfaced, never coerced. Polymarket only."
          },
          "trending_pnl_usd": {
            "type": "number",
            "description": "Polymarket weekly/monthly P&L for the wallet in USD, taken from Polymarket's canonical leaderboard (data-api.polymarket.com/v2/leaderboard?time_period=week|month&sort_by=PNL). This is the ranking axis and the rows are returned in Polymarket's by-PNL order; it is the provider's number, not a locally summed realized-leaf total."
          },
          "window_volume_usd": {
            "type": "number",
            "description": "Both-sides cash volume over the window in USD, from Polymarket GET /v2/user-volume (volume_usdc). Omitted when Polymarket served no volume for the wallet: an absent observation, never zero. Polymarket tracks volume in whole UTC days, so this window is the whole-day span covering the requested one, which is not the exact span trending_pnl_usd was scored over."
          },
          "window_volume_shares": {
            "type": "number",
            "description": "Both-sides traded volume over the window in SHARES, from the Polymarket leaderboard row, whose own schema states the figure is never USD. Omitted when the row carried none."
          },
          "window_markets_traded": {
            "type": "integer"
          },
          "window_trade_days": {
            "type": "integer",
            "description": "Distinct in-window UTC trade days from our trades (0 if the winner is not in our DB)."
          },
          "grade": {
            "type": "string",
            "enum": ["S", "A", "B", "C", "D", "F"],
            "description": "All-time trader grade; a separate axis from streak_tier. Led by realized profit on sports and esports markets (the money actually banked, about 95 percent of the grade; since 2026-10-22, the sports and esports share of the wallet's realized P&L), with forecasting calibration, risk-adjusted returns, and consistency as the tie-breaker and proven-trader guardrails: any grade above C requires verified net-positive realized profit on those markets, and the top grades also require a real track record of resolved sports and esports markets plus a survivable drawdown. Relative, so it drifts as the cohort moves. Omitted when the trader is Unranked (fewer than 5 markets, or too little verified record to cohort-rank)."
          },
          "streak_tier": {
            "type": "string",
            "enum": ["hot", "rising", "neutral", "cooling", "cold"],
            "description": "Hot-streak tier (trailing-7d cross-sectional percentile). Omitted when there is no recent activity."
          },
          "in_scope_realized_pnl": {
            "type": "number",
            "description": "Additive (#29971): the wallet's sports and esports realized P&L in USD, the same figure as pnl.in_scope.realized_pnl on GET /api/v1/trader/{address} and the 0xinsider profile's Sports P&L, as of the board's last rebuild. Context only: it does not affect the ranking, which follows trending_pnl_usd. Omitted when the wallet is not in the 0xinsider database or has no sports and esports record yet: absent means not computed, never zero."
          },
          "all_time_pnl_usd": {
            "type": "number",
            "deprecated": true,
            "x-never-sent": true,
            "description": "Deprecated since 2026-10-27 and never sent. It was Polymarket's net total P&L over every Polymarket market of the wallet, and wallet figures cover sports and esports markets only (#29971). Read in_scope_realized_pnl."
          },
          "pnl_correction": {
            "$ref": "#/components/schemas/PnlCorrection",
            "deprecated": true,
            "x-never-sent": true,
            "description": "Deprecated since 2026-10-27 and never sent. It was the neg-risk conversion correction to the wallet-wide all_time_pnl_usd (#29971). Its sports and esports part is inside in_scope_realized_pnl."
          },
          "all_time_score": {
            "type": "number"
          },
          "last_synced": {
            "type": "string",
            "format": "date-time"
          },
          "daily_pnl_series": {
            "type": "array",
            "description": "The wallet's sports and esports realized P&L on each UTC day of the window, ascending, one point a day, pnl_usd 0 on a day with none: the same in-scope realized day series the trader P&L endpoint serves. Empty while daily_pnl_series_status is pending, which never means zero. It leaves out non-sports markets, so it does not sum to trending_pnl_usd, which is Polymarket's leaderboard figure across all markets.",
            "items": {
              "type": "object",
              "required": ["date", "pnl_usd"],
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "pnl_usd": {
                  "type": "number"
                }
              }
            }
          },
          "daily_pnl_series_status": {
            "type": "string",
            "enum": ["ready", "pending"],
            "description": "`ready` when daily_pnl_series is served; an all-zero one is a wallet with no sports or esports P&L in the window. `pending` when the wallet's sports and esports record does not carry its daily series yet, or the wallet is not in the 0xinsider database: daily_pnl_series is empty and never means zero. Retry later."
          }
        }
      },
      "TraderEsportsGameRecord": {
        "type": "object",
        "required": ["game", "series_slug", "wins", "decided", "win_rate", "status"],
        "properties": {
          "game": {
            "type": "string",
            "description": "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."
          },
          "series_slug": {
            "type": "string",
            "description": "The Polymarket series slug the record is keyed on: league-of-legends, counter-strike, dota-2, valorant, call-of-duty, honor-of-kings, mobile-legends-bang-bang, overwatch, rainbow-six-siege, rocket-league or starcraft-2. The stable key; game is the label."
          },
          "wins": {
            "type": "integer",
            "description": "Markets in this game the wallet closed with a profit."
          },
          "decided": {
            "type": "integer",
            "description": "Markets in this game it closed with a profit or a loss. A subset of the parent Esports record's decided: the two are read from the same daily rebuild."
          },
          "win_rate": {
            "type": ["number", "null"],
            "description": "wins / decided in [0,1], truncated to four decimals. Null when status is not_enough_data."
          },
          "status": {
            "type": "string",
            "enum": ["measured", "not_enough_data"],
            "description": "The same rule as the parent record: measured when decided cleared min_decided_for_win_rate, not_enough_data when the counts are real but the sample is under the floor. A chip on a market in this game shows this row's rate when it is measured and the Esports bucket's otherwise."
          }
        }
      },
      "TraderClv": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string",
            "description": "Wallet address, lowercase."
          },
          "basis_version": {
            "type": "string",
            "description": "The CLV definition, clv@v1, each trade's clv.basis_version."
          },
          "category": {
            "type": ["string", "null"],
            "description": "The category filter as sent, or null."
          },
          "excluded": {
            "type": "object",
            "required": ["in_play", "pending", "unavailable"],
            "properties": {
              "in_play": {
                "type": "integer"
              },
              "pending": {
                "type": "integer"
              },
              "unavailable": {
                "type": "integer"
              }
            },
            "description": "The window's trades that carry no CLV, by clv.status."
          },
          "from": {
            "type": "string",
            "format": "date-time",
            "description": "Window start, inclusive."
          },
          "id": {
            "type": "string",
            "description": "trd_-prefixed trader id."
          },
          "large_trades": {
            "type": "integer",
            "description": "Large trades in the window, every status."
          },
          "measured": {
            "type": "object",
            "required": [
              "trades",
              "markets",
              "size_usd",
              "mean_clv_cents",
              "stake_weighted_clv_cents",
              "share_beat_close",
              "market_mean_clv_cents",
              "market_ci95_cents"
            ],
            "properties": {
              "market_ci95_cents": {
                "anyOf": [
                  {
                    "type": "object",
                    "required": ["low", "high"],
                    "properties": {
                      "high": {
                        "type": "number"
                      },
                      "low": {
                        "type": "number"
                      }
                    }
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Normal 95% interval on market_mean_clv_cents from the markets' sample deviation, as low and high. null below two markets."
              },
              "market_mean_clv_cents": {
                "type": ["number", "null"],
                "description": "Mean over markets of each market's mean clv_cents. null with no measured trade."
              },
              "markets": {
                "type": "integer",
                "description": "Distinct markets among them."
              },
              "mean_clv_cents": {
                "type": ["number", "null"],
                "description": "Plain mean of clv_cents. null with no measured trade."
              },
              "share_beat_close": {
                "type": ["number", "null"],
                "description": "Share of measured trades with clv_cents > 0, 0 to 1. null with no measured trade."
              },
              "size_usd": {
                "type": "number",
                "description": "Their summed size in USDC."
              },
              "stake_weighted_clv_cents": {
                "type": ["number", "null"],
                "description": "Mean of clv_cents weighted by each trade's size_usd. null with no measured trade."
              },
              "trades": {
                "type": "integer",
                "description": "Large trades with clv.status measured."
              }
            },
            "description": "Figures over the trades whose clv.status is measured."
          },
          "min_size": {
            "type": "number",
            "description": "Size floor in USDC, as /large-trades/history reads it."
          },
          "to": {
            "type": "string",
            "format": "date-time",
            "description": "Window end, exclusive."
          }
        },
        "required": [
          "id",
          "address",
          "from",
          "to",
          "min_size",
          "category",
          "basis_version",
          "large_trades",
          "measured",
          "excluded"
        ],
        "description": "Closing line value over one wallet's large trades in a window (#32517)."
      },
      "TraderGradeAt": {
        "type": "object",
        "required": ["id", "address", "as_of", "status", "grade", "available_from", "observation"],
        "properties": {
          "id": {
            "type": "string",
            "description": "Prefixed trader id (trd_<wallet>)."
          },
          "address": {
            "type": "string",
            "description": "Resolved wallet address, lowercased."
          },
          "as_of": {
            "type": "string",
            "format": "date-time",
            "description": "Requested event or decision time."
          },
          "status": {
            "type": "string",
            "enum": ["graded", "ungraded", "unknown"],
            "description": "graded has a proven grade; ungraded is a proven null grade; unknown has no valid historical observation."
          },
          "grade": {
            "type": ["string", "null"],
            "enum": ["S", "A", "B", "C", "D", "F", null],
            "description": "Grade only when status is graded; null otherwise."
          },
          "available_from": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "First proven visibility instant for this trader. Null when no observation exists. Earlier times remain unknown."
          },
          "observation": {
            "type": ["object", "null"],
            "required": [
              "id",
              "previous_observation_id",
              "observed_at",
              "published_by",
              "model_version",
              "model_build_sha",
              "source_observed_by"
            ],
            "description": "Proof row when status is graded or ungraded. Null when history is unknown.",
            "properties": {
              "id": {
                "type": "integer",
                "format": "int64",
                "description": "Immutable grade_forward_history observation id."
              },
              "previous_observation_id": {
                "type": ["integer", "null"],
                "format": "int64",
                "description": "Previous immutable observation id when retained. A later grade change supersedes that observation but never erases it; this link does not assert why the grade changed."
              },
              "observed_at": {
                "type": "string",
                "format": "date-time",
                "description": "Lower bound: the grade writer had started the transition at this instant."
              },
              "published_by": {
                "type": "string",
                "format": "date-time",
                "description": "Upper bound: a later snapshot confirmed the observation was committed. This is not an exact commit timestamp."
              },
              "model_version": {
                "type": ["string", "null"],
                "description": "Writer-proven model family, such as grading. Null when unknown."
              },
              "model_build_sha": {
                "type": ["string", "null"],
                "description": "Exact writer build SHA when recorded. Null on old and non-model observations."
              },
              "source_observed_by": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "Database-clock upper bound on when the grading pass read its cohort inputs. Not the event time or source freshness of every input; null when unknown."
              }
            }
          }
        }
      },
      "TraderCategoryRecord": {
        "type": "object",
        "required": ["category", "wins", "decided", "win_rate", "status"],
        "properties": {
          "category": {
            "type": "string",
            "description": "Canonical category bucket, for example Soccer, Esports, Tennis. Esports is one bucket, and the Esports record carries its per-game records in games. Every record carries its per-scope records (esports titles, soccer leagues, other sports' leagues) in scopes."
          },
          "wins": {
            "type": "integer",
            "description": "Markets in this category the wallet closed with a profit."
          },
          "decided": {
            "type": "integer",
            "description": "Markets it closed with a profit or a loss. A market that resolved at exactly zero P&L is in neither count, so this is not the wallet's market count in the category."
          },
          "win_rate": {
            "type": ["number", "null"],
            "description": "wins / decided in [0,1], truncated to four decimals. Null when status is not_enough_data."
          },
          "status": {
            "type": "string",
            "enum": ["measured", "not_enough_data"],
            "description": "measured: decided cleared min_decided_for_win_rate and win_rate carries the rate. not_enough_data: the counts are real but the sample is under the floor, so no percent is published. A failed read is an error response, never a status value."
          },
          "games": {
            "type": "array",
            "description": "The wallet's record per esports title, busiest first. Present only on the Esports record, and only when the wallet has a settled market in at least one title; absent on every other category and on an Esports record whose markets are all in series that are not games (skin-price indices, streamer props) or carry no series. Absent means no per-game record, the same rule as an absent category. Each entry's decided is a subset of the Esports record's, read in the same statement from the same daily rebuild.",
            "items": {
              "$ref": "#/components/schemas/TraderEsportsGameRecord"
            }
          },
          "scopes": {
            "type": "array",
            "description": "The wallet's record per scope of this category, busiest first: each esports title on the Esports record, each soccer league on the Soccer record (UEFA Champions League, LaLiga, Premier League, ...), and each registered league of another sport on its record (NBA, NFL, ATP, ...). The same records Pick of the Day and the holder chips name in category_win_rate_game. Present only when the wallet has a settled market in at least one scope; absent means no per-scope record, the same rule as an absent category. On the Esports record it lists the same titles as games, with the same counts. Each entry's decided is a subset of its record's, read in the same statement from the same daily rebuild.",
            "items": {
              "$ref": "#/components/schemas/TraderCategoryScopeRecord"
            }
          }
        }
      },
      "TraderCategoryScopeRecord": {
        "type": "object",
        "required": ["scope_key", "display_name", "wins", "decided", "win_rate", "status"],
        "properties": {
          "scope_key": {
            "type": "string",
            "description": "The stable key the scope's record is stored under: an esports series slug (league-of-legends, counter-strike), a soccer league's season-stripped series stem (ucl, la-liga, premier-league), or another sport's league stem (nba, nfl, atp). display_name is the label."
          },
          "display_name": {
            "type": "string",
            "description": "The scope's name as Pick of the Day and every holder chip print it in category_win_rate_game: LoL, CS2, UEFA Champions League, LaLiga, NBA. Match a chip to this row by string equality."
          },
          "wins": {
            "type": "integer",
            "description": "Markets in this scope the wallet closed with a profit."
          },
          "decided": {
            "type": "integer",
            "description": "Markets in this scope it closed with a profit or a loss. A subset of the parent record's decided: the two are read from the same daily rebuild."
          },
          "win_rate": {
            "type": ["number", "null"],
            "description": "wins / decided in [0,1], truncated to four decimals. Null when status is not_enough_data."
          },
          "status": {
            "type": "string",
            "enum": ["measured", "not_enough_data"],
            "description": "The same rule as the parent record: measured when decided cleared min_decided_for_win_rate, not_enough_data when the counts are real but the sample is under the floor. A chip on a market in this scope shows this row's rate when it is measured and the parent record's otherwise."
          }
        }
      },
      "TraderCategoryRecords": {
        "type": "object",
        "required": [
          "id",
          "address",
          "basis",
          "min_decided_for_win_rate",
          "computed_at",
          "records"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Prefixed trader id (trd_<wallet>)."
          },
          "address": {
            "type": "string",
            "description": "Resolved wallet address, lowercased."
          },
          "basis": {
            "type": "string",
            "enum": ["settled_markets_all_sizes"],
            "description": "Which sample the counts come from: every settled market in the category, at any position size. category_strengths on the trader endpoint reads the floored calibration sample instead, so the two differ in both directions: measured on production 2026-09-22 over the 122,497 wallet-category pairs with at least 20 decided markets on both bases, the floored rate was higher in 56.5% of pairs and lower in 34.5%, median +0.6 points, p10 -4.6, p90 +9.8, with 14.0% of pairs 10 points apart or more. Neither corrects the other."
          },
          "min_decided_for_win_rate": {
            "type": "integer",
            "description": "Decided markets a category needs before win_rate is served. Published so a caller can apply its own sample rule to the raw counts."
          },
          "computed_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When the served records were last rebuilt (RFC3339, Z): the newest stamp among every row served, game and scope rows included, which the daily rebuild writes in one transaction. Null when the wallet has no record at all."
          },
          "records": {
            "type": "array",
            "description": "One entry per canonical category with at least one decided market, ordered by decided descending then category. A category with no decided market is omitted. The Esports entry carries its per-game records in games, and every entry its per-scope records in scopes.",
            "items": {
              "$ref": "#/components/schemas/TraderCategoryRecord"
            }
          }
        }
      },
      "TraderPnl": {
        "type": "object",
        "description": "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.",
        "required": ["id", "freshness_at", "series_status", "realized"],
        "properties": {
          "id": {
            "type": "string",
            "description": "Prefixed trader ID (`trd_...`)."
          },
          "view": {
            "type": "object",
            "description": "Representation parameters applied to this body. Present only when the request sent `from`, `to` or `sections`; omitted otherwise, which is what keeps a no-parameter response identical to the one this route served before the parameters existed.",
            "required": ["from", "to", "sections", "entries_total", "entries_in_window", "anchor"],
            "additionalProperties": false,
            "properties": {
              "from": {
                "type": ["string", "null"],
                "format": "date",
                "description": "Inclusive UTC lower bound applied to the daily series; null when the request left the series unbounded below."
              },
              "to": {
                "type": ["string", "null"],
                "format": "date",
                "description": "Inclusive UTC upper bound applied to the daily series; null when the request left the series unbounded above."
              },
              "sections": {
                "type": "array",
                "description": "Sections this body carries, in the order the object publishes them, whatever order the query listed.",
                "items": {
                  "type": "string",
                  "enum": ["entries", "stats", "monthly", "year_totals", "drawdown"]
                }
              },
              "entries_total": {
                "type": "integer",
                "description": "Points in the full stored daily series, before the window. Compare with entries_in_window to tell a clipped chart from a wallet that really has that many days."
              },
              "entries_in_window": {
                "type": "integer",
                "description": "Points of the daily series inside the window. Equal to entries_total when no bound narrowed it, and reported whether or not entries was among the requested sections."
              },
              "anchor": {
                "type": ["object", "null"],
                "description": "The last daily point strictly before `from`: the cumulative baseline the window was cut away from. null when the request set no lower bound, or when the window starts at or before the first stored point and the slice already begins at the start of the history. Cumulative values in `entries` and `drawdown` are never rebased to the window, so this is the figure to subtract for a window-relative change.",
                "required": ["date", "cumulative_profit", "total_pnl", "drawdown"],
                "additionalProperties": false,
                "properties": {
                  "date": {
                    "type": "string",
                    "format": "date"
                  },
                  "cumulative_profit": {
                    "type": ["number", "null"],
                    "description": "Cumulative profit carried into the window; null when the stored point has none, the same nullability entries[].cumulative_profit has."
                  },
                  "total_pnl": {
                    "type": ["number", "null"],
                    "description": "Cumulative total P&L carried into the window; null on the same terms."
                  },
                  "drawdown": {
                    "type": ["number", "null"],
                    "description": "Underwater value at the anchor date; null when that date has no drawdown point, which happens exactly when its cumulative_profit is null. The running peak behind the window is cumulative_profit minus drawdown (drawdown is zero or negative)."
                  }
                }
              }
            }
          },
          "freshness_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "RFC3339 served-freshness clock: when the wallet's sports and esports record, which this series is read from, was last computed, or, for a wallet that traded no sports or esports market (#30589, #30657) or trades only combos (#30637) and so has no record, its last completed sync; null while series_status is pending. Always present, so read it as a value that can be null rather than a key that can be missing."
          },
          "series_status": {
            "type": "string",
            "enum": ["ready", "pending"],
            "description": "`ready` when the series is served; an empty one is a wallet with no sports or esports day, or one that traded no sports or esports market (#30589, #30657) or trades only combos (#30637). `pending` when the wallet's sports and esports record does not carry the daily series yet: every section is empty, realized is null, and the empty sections never mean zero. Retry later."
          },
          "realized": {
            "type": ["object", "null"],
            "description": "How the daily series adds up to the wallet's Sports P&L, full precision: dated_pnl + undated_pnl = realized_pnl. null while series_status is pending, and for a wallet that traded no sports or esports market or trades only combos, which has no record (#30589, #30657, #30637).",
            "required": ["basis", "realized_pnl", "dated_pnl", "undated_pnl"],
            "additionalProperties": false,
            "properties": {
              "basis": {
                "type": "string",
                "enum": ["polymarket_sports_esports_v1", "sports_esports_split_v1"],
                "description": "The rule behind realized_pnl, the same basis as pnl.in_scope.basis on GET /api/v1/trader/{address}."
              },
              "realized_pnl": {
                "type": ["number", "null"],
                "description": "The wallet's Sports P&L: pnl.in_scope.realized_pnl on GET /api/v1/trader/{address}. null when the wallet has no published realized figure."
              },
              "dated_pnl": {
                "type": "number",
                "description": "The sum of every day's daily_change over the full history, whatever from/to say."
              },
              "undated_pnl": {
                "type": ["number", "null"],
                "description": "realized_pnl less dated_pnl. realized_pnl starts from Polymarket's figures under either basis (its sports and esports figures, or its published figure for the whole wallet split by cost) and the days from the per-market record, so undated_pnl holds the wallet's share of Polymarket rebates, the in-scope part of the neg-risk conversion correction, any market with no trade date, and the difference between Polymarket's figure and the per-market record, which on some wallets is most of it. null exactly when realized_pnl is."
              }
            }
          },
          "entries": {
            "type": "array",
            "description": "Sports and esports daily P&L series (oldest-first): one point for each UTC day with realized P&L or sports and esports volume. Present unless the request's `sections` excluded it, and clipped to `from`/`to` when either is set. cumulative_profit and total_pnl are the running sum of daily_change from the start of the history, so a clipped slice keeps the same economic meaning; view.anchor carries the point before the window.",
            "items": {
              "type": "object",
              "required": ["date", "daily_change"],
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "markets_traded": {
                  "type": "integer",
                  "description": "Sports and esports markets this wallet traded on this UTC day, counted from the fills 0xinsider stores for it. Omitted on a day whose stored fills include a market outside sports and esports (stored before October 2026), where the count would include it, and on a day above 20 times the wallet's median day."
                },
                "total_volume": {
                  "type": "number",
                  "description": "Volume in USD this wallet traded on this UTC day in sports and esports markets, buys and sells: each fill's size times its price, fees excluded, the measure of Polymarket user-volume `volume_usdc`, summed from the fills 0xinsider stores for it. A day stored before 2026-10-27 counts the cash each fill moved, fee included, until it is recomputed. Not Polymarket's share count, and not the full-history stats.total_volume on GET /api/v1/trader/{address}, which covers every market. Omitted on a day with realized P&L and no stored sports or esports fill, and, with markets_traded, on a day above 20 times the wallet's median day."
                },
                "cumulative_profit": {
                  "type": "number",
                  "description": "Running sum of daily_change through this day."
                },
                "total_pnl": {
                  "type": "number",
                  "description": "The same running sum as cumulative_profit."
                },
                "daily_change": {
                  "type": "number",
                  "description": "Realized P&L of the wallet's sports and esports markets dated to this UTC day: a settled market on its resolution day, else its last trade day; an open market's realized part on its last trade day. 0 on a day with volume and nothing realized."
                }
              }
            }
          },
          "stats": {
            "type": "object",
            "description": "Pre-derived period stats. Present unless the request's `sections` excluded it. Always the published all/90d/30d/7d windows over the full stored history; `from`/`to` never recompute them over the request's range.",
            "required": ["all", "d90", "d30", "d7"],
            "properties": {
              "all": {
                "type": "object",
                "required": [
                  "current",
                  "change",
                  "change_pct",
                  "best_day",
                  "worst_day",
                  "win_days",
                  "loss_days",
                  "avg_day",
                  "rebase_anchor"
                ],
                "properties": {
                  "current": {
                    "type": "number"
                  },
                  "change": {
                    "type": "number"
                  },
                  "change_pct": {
                    "type": "number"
                  },
                  "best_day": {
                    "type": "number"
                  },
                  "best_day_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "worst_day": {
                    "type": "number"
                  },
                  "worst_day_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "win_days": {
                    "type": "integer"
                  },
                  "loss_days": {
                    "type": "integer"
                  },
                  "avg_day": {
                    "type": "number"
                  },
                  "rebase_anchor": {
                    "type": "number"
                  }
                }
              },
              "d90": {
                "type": "object",
                "required": [
                  "current",
                  "change",
                  "change_pct",
                  "best_day",
                  "worst_day",
                  "win_days",
                  "loss_days",
                  "avg_day",
                  "rebase_anchor"
                ],
                "properties": {
                  "current": {
                    "type": "number"
                  },
                  "change": {
                    "type": "number"
                  },
                  "change_pct": {
                    "type": "number"
                  },
                  "best_day": {
                    "type": "number"
                  },
                  "best_day_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "worst_day": {
                    "type": "number"
                  },
                  "worst_day_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "win_days": {
                    "type": "integer"
                  },
                  "loss_days": {
                    "type": "integer"
                  },
                  "avg_day": {
                    "type": "number"
                  },
                  "rebase_anchor": {
                    "type": "number"
                  }
                }
              },
              "d30": {
                "type": "object",
                "required": [
                  "current",
                  "change",
                  "change_pct",
                  "best_day",
                  "worst_day",
                  "win_days",
                  "loss_days",
                  "avg_day",
                  "rebase_anchor"
                ],
                "properties": {
                  "current": {
                    "type": "number"
                  },
                  "change": {
                    "type": "number"
                  },
                  "change_pct": {
                    "type": "number"
                  },
                  "best_day": {
                    "type": "number"
                  },
                  "best_day_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "worst_day": {
                    "type": "number"
                  },
                  "worst_day_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "win_days": {
                    "type": "integer"
                  },
                  "loss_days": {
                    "type": "integer"
                  },
                  "avg_day": {
                    "type": "number"
                  },
                  "rebase_anchor": {
                    "type": "number"
                  }
                }
              },
              "d7": {
                "type": "object",
                "required": [
                  "current",
                  "change",
                  "change_pct",
                  "best_day",
                  "worst_day",
                  "win_days",
                  "loss_days",
                  "avg_day",
                  "rebase_anchor"
                ],
                "properties": {
                  "current": {
                    "type": "number"
                  },
                  "change": {
                    "type": "number"
                  },
                  "change_pct": {
                    "type": "number"
                  },
                  "best_day": {
                    "type": "number"
                  },
                  "best_day_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "worst_day": {
                    "type": "number"
                  },
                  "worst_day_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "win_days": {
                    "type": "integer"
                  },
                  "loss_days": {
                    "type": "integer"
                  },
                  "avg_day": {
                    "type": "number"
                  },
                  "rebase_anchor": {
                    "type": "number"
                  }
                }
              }
            }
          },
          "monthly": {
            "type": "array",
            "description": "Per-month P&L aggregation. Present unless the request's `sections` excluded it. Whole months over the full stored history, never clipped to `from`/`to`, so a month is never a partial month.",
            "items": {
              "type": "object",
              "required": ["year", "month", "pnl", "markets_traded"],
              "properties": {
                "year": {
                  "type": "integer"
                },
                "month": {
                  "type": "integer"
                },
                "pnl": {
                  "type": "number"
                },
                "markets_traded": {
                  "type": ["integer", "null"],
                  "description": "The month's entries[].markets_traded summed: a market traded on several days counts once a day. null when a day of the month has total_volume and no markets_traded, a day whose stored fills include a market outside sports and esports, where a sum would undercount. A day with no stored fill, or above 20 times the wallet's median day, adds 0."
                }
              }
            }
          },
          "year_totals": {
            "type": "array",
            "description": "Per-year P&L totals (ascending by year). Present unless the request's `sections` excluded it. Whole years over the full stored history, never clipped to `from`/`to`.",
            "items": {
              "type": "object",
              "required": ["year", "pnl"],
              "properties": {
                "year": {
                  "type": "integer"
                },
                "pnl": {
                  "type": "number"
                }
              }
            }
          },
          "drawdown": {
            "type": "array",
            "description": "Underwater (drawdown) series. Present unless the request's `sections` excluded it, and clipped to `from`/`to` when either is set. The running peak behind each point is the full-history peak, so a clipped slice is not rebased; view.anchor.drawdown carries the value at the point before the window.",
            "items": {
              "type": "object",
              "required": ["date", "cumulative_profit", "drawdown"],
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "cumulative_profit": {
                  "type": "number"
                },
                "drawdown": {
                  "type": "number"
                }
              }
            }
          }
        }
      },
      "McpJsonRpcError": {
        "type": "object",
        "required": ["jsonrpc", "error"],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "description": "The request's id, or null when the request could not be parsed. Omitted on the answer to an unsolicited response message.",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": {
              "code": {
                "type": "integer"
              },
              "message": {
                "type": "string"
              },
              "data": {
                "description": "Optional JSON-serializable error data.",
                "oneOf": [
                  {
                    "type": "object"
                  },
                  {
                    "type": "array"
                  },
                  {
                    "type": "string"
                  },
                  {
                    "type": "number"
                  },
                  {
                    "type": "boolean"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          }
        }
      },
      "ProofPendingPickSlot": {
        "type": "object",
        "description": "One PUBLISHED same-day pick whose holder proof is not readable yet: its stable slot rank, the release and kickoff instants, and the instant before which a retry cannot succeed. Every item in `picks` carries its full required shape, so a pick that cannot meet it is listed here instead of being served with missing fields or a synthetic zero.",
        "required": [
          "pick_rank",
          "release_at",
          "retry_at",
          "pick_id",
          "publication_order",
          "is_free_selection",
          "supersedes_pick_id"
        ],
        "properties": {
          "pick_rank": {
            "type": "integer",
            "minimum": 1,
            "maximum": 30,
            "description": "Deprecated compatibility daily release slot; use pick_id for identity and publication_order for scheduling.",
            "deprecated": true
          },
          "release_at": {
            "type": "string",
            "format": "date-time",
            "description": "The pick's stored release instant."
          },
          "kickoff": {
            "type": "string",
            "format": "date-time",
            "description": "The backed game's frozen kickoff instant; absent for a legacy row without one."
          },
          "retry_at": {
            "type": "string",
            "format": "date-time",
            "description": "Recommended next read: 30 seconds ahead while pre-game proof is warming, one hour ahead for a post-kickoff pending legacy row that only settlement can make readable. Schedule against it instead of polling."
          },
          "pick_id": {
            "type": "string",
            "pattern": "^[1-9][0-9]*$",
            "description": "Stable pick row identity as decimal text. Never use a quality rank as identity."
          },
          "publication_order": {
            "type": "integer",
            "description": "Compatibility release slot. No quality claim; historic scheduling order is retained."
          },
          "is_free_selection": {
            "type": "boolean",
            "description": "Viewer-independent free selection designation. New rows store it explicitly; historic null storage uses the original free slot."
          },
          "supersedes_pick_id": {
            "deprecated": true,
            "type": ["string", "null"],
            "pattern": "^[1-9][0-9]*$",
            "description": "Deprecated (#24157): always null. No replacement lineage was ever recorded in this field; the key stays so existing V1 clients keep parsing. Identify a pick by pick_id."
          }
        }
      },
      "PotdEntryAuthorization": {
        "type": "object",
        "required": [
          "version",
          "authorization_id",
          "policy_version",
          "condition_id",
          "token_id",
          "outcome_index",
          "category",
          "canonical_event_id",
          "max_entry_price",
          "reference_best_ask",
          "reference_book_hash",
          "reference_book_at",
          "issued_at",
          "expires_at"
        ],
        "properties": {
          "version": {
            "type": "integer",
            "enum": [1]
          },
          "authorization_id": {
            "type": "string",
            "format": "uuid"
          },
          "policy_version": {
            "type": "integer",
            "enum": [7, 8],
            "description": "Identifier for the policy recorded with this authorization. It does not replace the returned max_entry_price or expires_at. Existing grants retain their recorded values."
          },
          "condition_id": {
            "type": "string"
          },
          "token_id": {
            "type": "string"
          },
          "outcome_index": {
            "type": "integer",
            "enum": [0, 1]
          },
          "category": {
            "type": "string",
            "description": "Canonical sport bucket, not display_category."
          },
          "canonical_event_id": {
            "type": "string",
            "description": "Exact provider parent event ID, or provider event ID when no parent exists."
          },
          "max_entry_price": {
            "type": "string",
            "description": "Maximum authorized order price as an exact decimal string, excluding fees. Quote a current executable book for the actual stake and keep the submitted order price at or below this bound. Actual fills may be lower; this limit does not guarantee a fill or define fair probability."
          },
          "reference_best_ask": {
            "type": "string",
            "description": "Selected-token best ask from the recorded reference book at issuance. This is a reference quote, not the authorized order-price limit; use max_entry_price for that limit."
          },
          "reference_book_hash": {
            "type": "string"
          },
          "reference_book_at": {
            "type": "string",
            "format": "date-time"
          },
          "issued_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Authorization expiry timestamp. Existing grants do not extend; an expired authorization cannot authorize a new automated entry."
          }
        },
        "description": "Returned entry permission bound to the named market, token and outcome. Honor the immutable max_entry_price and expires_at, and quote a current executable book for the actual stake. The submitted order price must remain within the returned limit; fills may be lower. Fees are separate, and this grant does not guarantee liquidity, execution or positive expected value."
      },
      "AgentRegistration": {
        "type": "object",
        "description": "A sandbox key and the path to live access (#13959). Nothing is stored: the key cannot be listed or revoked and does not expire. Register again for a new one.",
        "required": ["api_key", "livemode", "environment", "created_at", "sandbox", "live_access"],
        "properties": {
          "api_key": {
            "type": "string",
            "pattern": "^oxi_sk_test_[0-9a-f]{64}$",
            "description": "The sandbox key. Send it as Authorization: Bearer <api_key> to the sandbox. The last 8 hex characters are a checksum (the first 4 bytes of SHA-256 over the rest of the key), so the sandbox can tell a mistyped key from a real one. It is not a secret and unlocks no production data."
          },
          "livemode": {
            "type": "boolean",
            "const": false,
            "description": "Always false: this key never reaches live data."
          },
          "environment": {
            "type": "string",
            "const": "sandbox"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "sandbox": {
            "type": "object",
            "required": ["api_base_url", "first_request_url", "openapi_url"],
            "properties": {
              "api_base_url": {
                "type": "string",
                "format": "uri",
                "description": "The sandbox V1 base URL. Every documented operation answers here with example data, except GET /api/v1/stream: a Server-Sent Events stream is a live connection rather than a body, so the sandbox answers it with 400."
              },
              "first_request_url": {
                "type": "string",
                "format": "uri",
                "description": "A read to send with the key."
              },
              "openapi_url": {
                "type": "string",
                "format": "uri",
                "description": "The OpenAPI document, served by the sandbox."
              }
            }
          },
          "live_access": {
            "type": "object",
            "description": "What live data needs, and where each credential comes from. Both need a person: an account with an active Pro subscription.",
            "required": [
              "api_base_url",
              "requirement",
              "api_keys_url",
              "oauth_authorization_server_metadata_url",
              "oauth_registration_endpoint",
              "pricing_url",
              "auth_guide_url"
            ],
            "properties": {
              "api_base_url": {
                "type": "string",
                "format": "uri",
                "description": "The production V1 base URL."
              },
              "requirement": {
                "type": "string",
                "description": "What a live credential needs, in one sentence."
              },
              "api_keys_url": {
                "type": "string",
                "format": "uri",
                "description": "Where a signed-in Pro user creates a live key (oxi_sk_live_)."
              },
              "oauth_authorization_server_metadata_url": {
                "type": "string",
                "format": "uri",
                "description": "RFC 8414 authorization server metadata, for an OAuth 2.1 grant the user approves."
              },
              "oauth_registration_endpoint": {
                "type": "string",
                "format": "uri",
                "description": "RFC 7591 dynamic client registration for public OAuth clients."
              },
              "pricing_url": {
                "type": "string",
                "format": "uri",
                "description": "The Pro plan."
              },
              "auth_guide_url": {
                "type": "string",
                "format": "uri",
                "description": "The authentication walkthrough for agents."
              }
            }
          }
        }
      },
      "AccountIdentity": {
        "type": "object",
        "required": ["object", "data", "meta"],
        "properties": {
          "object": {
            "type": "string",
            "enum": ["account"]
          },
          "data": {
            "type": "object",
            "required": [
              "user_id",
              "credential_id",
              "credential_kind",
              "credential_status",
              "entitlement",
              "scopes"
            ],
            "properties": {
              "user_id": {
                "type": "integer"
              },
              "credential_id": {
                "type": "integer"
              },
              "credential_kind": {
                "type": "string",
                "enum": ["api_key", "oauth_grant", "integration_key"],
                "description": "The kind of credential that made the request: api_key is a full-access developer key, oauth_grant an OAuth access token, integration_key a named integration key with fixed scopes created on https://0xinsider.com/developers. Before integration_key was added, these keys reported oauth_grant."
              },
              "credential_status": {
                "type": "string",
                "const": "active",
                "description": "The credential is currently valid; revoked, expired or unknown credentials are rejected."
              },
              "entitlement": {
                "type": "object",
                "required": ["paid_data_access", "recovery_action"],
                "properties": {
                  "paid_data_access": {
                    "type": "string",
                    "enum": ["active", "lapsed"]
                  },
                  "recovery_action": {
                    "type": ["string", "null"],
                    "enum": ["renew_subscription", null],
                    "description": "When paid data access is lapsed, the caller should renew the subscription; otherwise null."
                  }
                }
              },
              "scopes": {
                "type": ["array", "null"],
                "items": {
                  "type": "string"
                },
                "description": "The scopes an OAuth grant or integration key carries; null for full developer-key access."
              }
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        }
      },
      "CategorySkillV2": {
        "type": "object",
        "description": "Forward-only category evidence from observed Polymarket taker fills. Status is category eligibility, not a global letter grade or a guarantee of positive edge. Scores are probability differences. Unknown and degraded rows withhold scores. Coverage is partial; observation counts are not lifetime market counts.",
        "required": [
          "status",
          "model_version",
          "taxonomy_version",
          "platform",
          "scope",
          "source_coverage",
          "canonical_category",
          "as_of",
          "source_last_success_at",
          "observation_started_at",
          "latest_observation_at",
          "independent_event_count",
          "resolved_condition_count",
          "unresolved_observation_count",
          "edge_mean",
          "edge_sd",
          "edge_se",
          "edge_lower_95",
          "brier_event_avg"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["live", "insufficient", "stale", "unknown", "degraded"]
          },
          "model_version": {
            "type": "string"
          },
          "taxonomy_version": {
            "type": ["string", "null"]
          },
          "platform": {
            "type": "string",
            "enum": ["polymarket"]
          },
          "scope": {
            "type": "string",
            "enum": ["observed_goldsky_primary_taker_fill"]
          },
          "source_coverage": {
            "type": "string",
            "enum": ["partial_whale_threshold_fills", "graded_wallet_fills"]
          },
          "canonical_category": {
            "type": "string"
          },
          "as_of": {
            "type": "string",
            "format": "date-time"
          },
          "source_last_success_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "observation_started_at": {
            "type": "string",
            "format": "date-time"
          },
          "latest_observation_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "independent_event_count": {
            "type": "integer",
            "minimum": 0
          },
          "resolved_condition_count": {
            "type": "integer",
            "minimum": 0
          },
          "unresolved_observation_count": {
            "type": "integer",
            "minimum": 0
          },
          "edge_mean": {
            "type": ["number", "null"]
          },
          "edge_sd": {
            "type": ["number", "null"]
          },
          "edge_se": {
            "type": ["number", "null"]
          },
          "edge_lower_95": {
            "type": ["number", "null"]
          },
          "brier_event_avg": {
            "type": ["number", "null"]
          }
        }
      },
      "CategorySkillModelReadiness": {
        "type": "object",
        "required": [
          "status",
          "model_version",
          "taxonomy_version",
          "observation_started_at",
          "as_of",
          "source_last_success_at"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["live", "insufficient", "stale", "unknown", "degraded"]
          },
          "model_version": {
            "type": "string"
          },
          "taxonomy_version": {
            "type": "string"
          },
          "observation_started_at": {
            "type": "string",
            "format": "date-time"
          },
          "as_of": {
            "type": "string",
            "format": "date-time"
          },
          "source_last_success_at": {
            "type": ["string", "null"],
            "format": "date-time"
          }
        },
        "description": "Model-wide readiness, read in the same database snapshot as category_records. Individual category rows retain their own status."
      },
      "HolderCategoryEvidence": {
        "type": "object",
        "required": ["status"],
        "description": "Current category evidence, independent of the global grade. Pick of the Day stamps only the served display roster; frozen entry snapshots remain unchanged.",
        "properties": {
          "status": {
            "type": "string",
            "enum": ["live", "insufficient", "stale", "unknown", "degraded"]
          },
          "canonical_category": {
            "type": "string"
          },
          "skill": {
            "$ref": "#/components/schemas/CategorySkillV2"
          }
        }
      },
      "WhaleDatasetFilters": {
        "type": "object",
        "required": ["from", "to", "condition_id", "min_size_cents"],
        "properties": {
          "from": {
            "type": "string",
            "format": "date-time"
          },
          "to": {
            "type": "string",
            "format": "date-time"
          },
          "condition_id": {
            "type": ["string", "null"]
          },
          "min_size_cents": {
            "type": ["integer", "null"],
            "minimum": 0
          }
        },
        "description": "Normalized immutable request; [from, to), maximum 31 days; min_size rounded to cents like durable replay."
      },
      "WhaleDatasetContinuation": {
        "type": "object",
        "required": [
          "path",
          "cursor",
          "from_commit_xid",
          "condition_id",
          "min_size",
          "deduplication_identity",
          "time_window_applies_to_deltas",
          "delivery"
        ],
        "properties": {
          "path": {
            "type": "string",
            "const": "/api/v1/events/feed/since"
          },
          "cursor": {
            "type": "string",
            "description": "Opaque commit-safe replay cursor; replay the same condition_id and min_size."
          },
          "from_commit_xid": {
            "type": "string",
            "description": "Writer floor included by the replay cursor. It can precede the snapshot horizon to include arrivals after the finite window end."
          },
          "condition_id": {
            "type": ["string", "null"]
          },
          "min_size": {
            "type": ["string", "null"],
            "description": "Normalized USD threshold; pass it to the replay query."
          },
          "deduplication_identity": {
            "type": "string"
          },
          "time_window_applies_to_deltas": {
            "type": "boolean",
            "const": false
          },
          "delivery": {
            "type": "string"
          }
        }
      },
      "WhaleDatasetGeneration": {
        "type": "object",
        "required": [
          "dataset_schema_version",
          "id",
          "selected_at",
          "consistency",
          "filters",
          "commit_horizon_xid",
          "continuation",
          "source",
          "coverage",
          "expires_at",
          "extraction_elapsed_ms"
        ],
        "properties": {
          "dataset_schema_version": {
            "type": "string",
            "const": "whale_dataset_v1"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "selected_at": {
            "type": "string",
            "format": "date-time"
          },
          "consistency": {
            "type": "string",
            "const": "repeatable_read_commit_horizon"
          },
          "filters": {
            "$ref": "#/components/schemas/WhaleDatasetFilters"
          },
          "commit_horizon_xid": {
            "type": "string",
            "description": "All snapshot rows have a writer xid strictly below this closed visibility horizon. Decimal string preserves integer precision."
          },
          "continuation": {
            "$ref": "#/components/schemas/WhaleDatasetContinuation"
          },
          "source": {
            "type": "string",
            "const": "whale_alerts"
          },
          "coverage": {
            "type": "string",
            "description": "Best-effort detected whale alerts only; not all provider fills. No trader or market enrichment."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "extraction_elapsed_ms": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "WhaleDatasetArtifactManifest": {
        "type": "object",
        "required": [
          "manifest_version",
          "format",
          "schema_version",
          "coverage",
          "generation",
          "row_count",
          "content_size_bytes",
          "content_sha256",
          "compressed_size_bytes",
          "compressed_sha256"
        ],
        "properties": {
          "manifest_version": {
            "type": "string",
            "description": "Version of the artifact manifest contract."
          },
          "format": {
            "type": "string",
            "const": "ndjson"
          },
          "schema_version": {
            "type": "string",
            "const": "whale_dataset_v1"
          },
          "coverage": {
            "type": "string",
            "const": "best_effort_detected_whale_alerts"
          },
          "generation": {
            "$ref": "#/components/schemas/WhaleDatasetGeneration",
            "x-narrowed": true
          },
          "row_count": {
            "type": "integer",
            "format": "int64",
            "description": "Number of trade rows written."
          },
          "content_size_bytes": {
            "type": "integer",
            "format": "int64",
            "description": "Exact byte count of the decompressed content stream clients receive."
          },
          "content_sha256": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "Lowercase SHA-256 of the decompressed content bytes."
          },
          "compressed_size_bytes": {
            "type": "integer",
            "format": "int64",
            "description": "Exact byte count of the gzip-compressed bytes stored by the object provider."
          },
          "compressed_sha256": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "Lowercase SHA-256 of the stored gzip bytes; the multipart ETag is not used as this checksum."
          }
        }
      },
      "WhaleDatasetJob": {
        "type": "object",
        "required": ["object", "data", "meta"],
        "properties": {
          "object": {
            "type": "string",
            "const": "whale_dataset_job"
          },
          "data": {
            "type": "object",
            "required": [
              "job_id",
              "status",
              "format",
              "total_trades",
              "processed_trades",
              "file_size",
              "error",
              "terminal",
              "next_action",
              "created_at",
              "started_at",
              "ready_at",
              "failed_at",
              "expires_at",
              "expired_at",
              "data_as_of",
              "cancel_requested_at",
              "cancelled_at",
              "attempt",
              "max_attempts",
              "filters"
            ],
            "properties": {
              "job_id": {
                "type": "integer",
                "format": "int64"
              },
              "status": {
                "type": "string",
                "enum": [
                  "queued",
                  "running",
                  "ready",
                  "failed",
                  "reconcile_required",
                  "expired",
                  "cancel_requested",
                  "cancelled"
                ],
                "description": "queued: waiting for a worker. A running job reads queued again, with error saying why, when its worker restarts for a deploy (the next worker claims it within seconds) or stops without handing it back (requeued within a minute of its 30-minute lease lapsing); it starts again from the beginning. running: the worker is streaming rows. reconcile_required: the upload finished but the storage completion answer was lost; the reconciler reads the object back within a minute, retries a failed readback an hour later, and moves the job to ready or failed, and expires_at bounds the wait. ready: downloadable until expires_at. failed: terminal; error says why; submit a new export. expired: the retention window passed; the file is retired, the download route answers 410, submit a new export. cancel_requested: the owner cancelled a running job (POST /api/v1/trader/{address}/export/cancel); the worker stops at its next safe point and the job reads cancelled. cancelled: terminal; the owner cancelled the job and no file was published; submit a new export. A job that has not reached ready by expires_at reads failed with error 'export expired before completion'. failed, cancelled and expired rows stay readable for 48 hours, then the job answers 404."
              },
              "format": {
                "type": "string",
                "const": "ndjson"
              },
              "total_trades": {
                "type": ["integer", "null"],
                "format": "int64"
              },
              "processed_trades": {
                "type": ["integer", "null"],
                "format": "int64"
              },
              "file_size": {
                "type": ["integer", "null"],
                "format": "int64"
              },
              "error": {
                "type": ["string", "null"]
              },
              "terminal": {
                "type": "boolean",
                "description": "True when status never changes again (ready, failed, expired, cancelled). Stop polling."
              },
              "next_action": {
                "type": "string",
                "enum": ["poll", "download", "resubmit"],
                "description": "What to do next: poll the status route after poll_after_s, follow the download route, or submit a new export. Published beside status so a status value added later does not strand a client."
              },
              "poll_after_s": {
                "type": "integer",
                "description": "Seconds to wait before polling again. Absent when terminal. 5 while queued, running or cancel_requested; 300 while reconcile_required, the cadence that state can change at."
              },
              "created_at": {
                "type": "string",
                "format": "date-time"
              },
              "started_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "When the worker last claimed the job; null while queued."
              },
              "ready_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "When the file became downloadable. null before ready, and on jobs finalized before this field existed."
              },
              "failed_at": {
                "type": ["string", "null"],
                "format": "date-time"
              },
              "expires_at": {
                "type": "string",
                "format": "date-time",
                "description": "The retention window: 24 hours from submit. A ready file downloads until this instant; a job that has not reached ready by it fails. A reused job (200 on submit) keeps its original window."
              },
              "expired_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "When the job became expired; null until then."
              },
              "data_as_of": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "Snapshot selection clock, null until the artifact is written; not provider completeness."
              },
              "cancel_requested_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "When the owner asked to cancel the job; null otherwise. Set on every cancelled job, including one cancelled while queued. While status is cancel_requested this is the instant the worker was asked to stop."
              },
              "cancelled_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "When the job reached cancelled; null until then."
              },
              "attempt": {
                "type": "integer",
                "description": "Worker claims so far. A claim handed back when its worker restarts for a deploy is not counted, so attempt steps back by one when the job reads queued again for that reason."
              },
              "max_attempts": {
                "type": "integer",
                "description": "The job fails when attempt reaches this."
              },
              "artifact": {
                "type": "object",
                "description": "Present only while status is ready: the stored object's identity, so a client can check the download it receives.",
                "required": [
                  "artifact_id",
                  "etag",
                  "compressed_size_bytes",
                  "content_type",
                  "content_encoding",
                  "manifest"
                ],
                "properties": {
                  "artifact_id": {
                    "type": "string",
                    "description": "Stable identity for this completed export artifact; unchanged when a temporary download URL is renewed."
                  },
                  "etag": {
                    "type": ["string", "null"],
                    "description": "The storage ETag of the object."
                  },
                  "compressed_size_bytes": {
                    "type": ["integer", "null"],
                    "format": "int64",
                    "description": "Bytes on the wire (gzip); file_size is the decompressed size."
                  },
                  "content_type": {
                    "type": "string",
                    "const": "application/x-ndjson"
                  },
                  "content_encoding": {
                    "type": "string",
                    "const": "gzip"
                  },
                  "manifest": {
                    "oneOf": [
                      {
                        "$ref": "#/components/schemas/WhaleDatasetArtifactManifest"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Immutable source, window, replay handoff, count and hashes of both content and gzip bytes."
                  }
                }
              },
              "filters": {
                "$ref": "#/components/schemas/WhaleDatasetFilters"
              }
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        }
      },
      "WhaleDatasetTrade": {
        "type": "object",
        "required": [
          "id",
          "sequence",
          "trader_id",
          "condition_id",
          "platform",
          "traded_at",
          "side",
          "outcome_index",
          "price",
          "size_usd",
          "inserted_xid",
          "trade_event_id",
          "source_trade_ingested_at",
          "clv"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "wt_<whale_alert_id>; deduplication identity shared with expanded replay."
          },
          "sequence": {
            "type": "string",
            "description": "Decimal whale-alert ID."
          },
          "trader_id": {
            "type": "string",
            "description": "trd_<local trader ID>."
          },
          "condition_id": {
            "type": "string"
          },
          "platform": {
            "type": "string",
            "const": "polymarket"
          },
          "traded_at": {
            "type": "string",
            "format": "date-time"
          },
          "side": {
            "type": "string",
            "enum": ["BUY", "SELL"]
          },
          "outcome_index": {
            "type": ["integer", "null"],
            "description": "Provider outcome index, null before the canonical outcome trust boundary."
          },
          "price": {
            "type": "string",
            "description": "Exact stored NUMERIC price; decimal string."
          },
          "size_usd": {
            "type": "string",
            "description": "Exact stored NUMERIC USD notional; decimal string."
          },
          "inserted_xid": {
            "type": "string",
            "description": "Writer transaction ID, decimal string."
          },
          "trade_event_id": {
            "type": "string",
            "description": "Stored source trade identity."
          },
          "source_trade_ingested_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "clv": {
            "type": "object",
            "required": [
              "status",
              "unavailable_reason",
              "pre_kickoff",
              "close_anchor_at",
              "close_price",
              "clv_cents",
              "basis_version",
              "taker_fee_cents",
              "clv_after_fees_cents"
            ],
            "properties": {
              "basis_version": {
                "type": "string",
                "description": "The CLV definition, clv@v1."
              },
              "close_anchor_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "The anchor pre_kickoff was judged against: the stored close's anchor, else the market's kickoff."
              },
              "close_price": {
                "type": ["number", "null"],
                "description": "The traded outcome's closing price, 0 to 1, whenever a usable close is stored and the outcome is known, in play included."
              },
              "clv_cents": {
                "type": ["number", "null"],
                "description": "Cents per share, positive when the trade beat the close: buy is (close_price - price) * 100, sell is (price - close_price) * 100. Gross of fees. Computed from the exact stored price this row carries, so a recomputation from price and close_price agrees to the stored digits. Set exactly when status is measured."
              },
              "pre_kickoff": {
                "type": ["boolean", "null"],
                "description": "Whether the trade filled before close_anchor_at. null when the market has no anchor."
              },
              "status": {
                "type": "string",
                "enum": ["measured", "in_play", "pending", "unavailable"],
                "description": "measured: clv_cents is set. in_play: traded at or after the close anchor (kickoff), no CLV is defined. pending: traded before kickoff and the market's close is not stored yet. unavailable: see unavailable_reason."
              },
              "unavailable_reason": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "no_observation_in_lookback",
                      "provider_empty_window",
                      "provider_invalid_contract",
                      "capture_window_closed",
                      "no_game_start_time",
                      "not_one_sided_resolution",
                      "not_captured",
                      "close_token_mismatch",
                      "anchor_stale",
                      "outcome_unknown"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Set exactly when status is unavailable. The market's reasons (see MarketClose.unavailable_reason), plus anchor_stale (the kickoff moved after the close was captured) and outcome_unknown (the traded outcome is not known for this trade)."
              },
              "clv_after_fees_cents": {
                "type": ["number", "null"],
                "description": "clv_cents - taker_fee_cents: the CLV after the fee the fill paid, cents per share. Set exactly when both are set."
              },
              "taker_fee_cents": {
                "type": ["number", "null"],
                "description": "The fee the fill paid as taker, cents per share, from the exchange's on-chain record of the fill (the OrderFilled event in its Polygon receipt); the trader is its taker. Polymarket charges only takers, so a buy's fee adds to its cost and a sell's comes out of its proceeds, and either way it lowers the CLV by this amount. Includes any builder fee an app added; excludes maker and taker rebates, which Polymarket pays later and no fill records. Set whatever status is; null until the record is decoded (about a minute after the trade) and for trades before 2026-08-16."
              }
            },
            "description": "Closing line value: the clv object of the same trade on /api/v1/large-trades, judged at the generation's selected_at from close states read inside the same snapshot. A pending row can be measured in a later generation. The close is stored once (GET /api/v1/market/{condition_id}/close), so a measured clv_cents changes only if the market's kickoff or YES token changes afterwards, which makes it unavailable (anchor_stale, close_token_mismatch)."
          }
        }
      },
      "PickOfTheDayCommitmentPayloadV1": {
        "type": "object",
        "description": "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.",
        "required": [
          "backed_price",
          "condition_id",
          "kickoff",
          "pick_date",
          "pick_outcome_index",
          "pick_outcome_label",
          "pick_rank",
          "platform"
        ],
        "properties": {
          "backed_price": {
            "type": "string",
            "description": "Frozen pre-game price of the backed side, 0..1, as the plain decimal text of the stored NUMERIC at full stored precision, trailing zeros included. A string, never a number: a float round-trip would change the bytes and break the hash. Deliberately not normalized -- 0.545000 stays \"0.545000\"."
          },
          "condition_id": {
            "type": "string",
            "description": "Provider condition id of the backed market."
          },
          "kickoff": {
            "type": "string",
            "format": "date-time",
            "description": "Frozen provider kickoff, whole seconds, UTC, literal Z. Fixed precision, never a shortest-lossless rendering."
          },
          "pick_date": {
            "type": "string",
            "format": "date",
            "description": "ET product day (YYYY-MM-DD)."
          },
          "pick_outcome_index": {
            "type": "integer",
            "enum": [0, 1],
            "description": "Index of the backed outcome within the market."
          },
          "pick_outcome_label": {
            "type": "string",
            "description": "Frozen display label of the backed outcome."
          },
          "pick_rank": {
            "type": "integer",
            "description": "1-based daily slot."
          },
          "platform": {
            "type": "string",
            "enum": ["polymarket"],
            "description": "Provider platform. Always polymarket."
          }
        }
      },
      "PickOfTheDayCommitmentPayloadV2": {
        "type": "object",
        "description": "Version 2 rank-free canonical payload: sorted nine keys, unchanged string escaping, exact decimal text and whole-second UTC kickoff. pick_id is decimal text; version is JSON integer 2.",
        "required": [
          "backed_price",
          "condition_id",
          "kickoff",
          "pick_date",
          "pick_outcome_index",
          "pick_outcome_label",
          "platform",
          "pick_id",
          "version"
        ],
        "properties": {
          "backed_price": {
            "type": "string",
            "description": "Frozen pre-game price of the backed side, 0..1, as the plain decimal text of the stored NUMERIC at full stored precision, trailing zeros included. A string, never a number: a float round-trip would change the bytes and break the hash. Deliberately not normalized -- 0.545000 stays \"0.545000\"."
          },
          "condition_id": {
            "type": "string",
            "description": "Provider condition id of the backed market."
          },
          "kickoff": {
            "type": "string",
            "format": "date-time",
            "description": "Frozen provider kickoff, whole seconds, UTC, literal Z. Fixed precision, never a shortest-lossless rendering."
          },
          "pick_date": {
            "type": "string",
            "format": "date",
            "description": "ET product day (YYYY-MM-DD)."
          },
          "pick_outcome_index": {
            "type": "integer",
            "enum": [0, 1],
            "description": "Index of the backed outcome within the market."
          },
          "pick_outcome_label": {
            "type": "string",
            "description": "Frozen display label of the backed outcome."
          },
          "platform": {
            "type": "string",
            "enum": ["polymarket"],
            "description": "Provider platform. Always polymarket."
          },
          "pick_id": {
            "type": "string",
            "pattern": "^[1-9][0-9]*$",
            "description": "Stable pick row identity as decimal text. Never use a quality rank as identity."
          },
          "version": {
            "type": "integer",
            "const": 2
          }
        }
      },
      "TennisPoints": {
        "type": "object",
        "description": "Optional current-game tennis facts from API-Tennis, aligned with live_score.scores display order. These facts have their own revision and expiry; Polymarket remains the source of sets, match status, period, and the outer live-score revision, except on ITF singles, which Polymarket does not score: there API-Tennis supplies the whole live_score, bound on both players' names, the tournament and the date. New observations require corroborated identity, current set/games, and live state. Where Polymarket publishes no score (tennis doubles, whose live_score reads one 0-0 set throughout), the group binds on both pairs' names, the tour, the date and API-Tennis's live flag, and carries set_games, the provider's set score for the match. Cached responses and replayed frames may still carry expired facts, so clients must enforce expires_at.",
        "required": [
          "source",
          "match_key",
          "player_keys",
          "points",
          "source_revision",
          "observed_at",
          "expires_at",
          "set_number",
          "games"
        ],
        "properties": {
          "source": {
            "type": "string",
            "enum": ["api_tennis"]
          },
          "match_key": {
            "type": "integer",
            "description": "API-Tennis match ID. This is not a Polymarket market or event ID."
          },
          "player_keys": {
            "type": "array",
            "minItems": 2,
            "maxItems": 2,
            "items": {
              "type": "integer"
            },
            "description": "API-Tennis player IDs in the same first/second order as live_score.scores. These are not Polymarket team IDs."
          },
          "points": {
            "type": "array",
            "minItems": 2,
            "maxItems": 2,
            "items": {
              "type": "string"
            },
            "description": "Current-game point values in first/second order. Read strings, including A for advantage and numeric tiebreak points. Missing points are not zero."
          },
          "serving_side": {
            "type": "string",
            "enum": ["first", "second"],
            "description": "The serving player in live_score.scores display order. Omitted when API-Tennis does not identify the server."
          },
          "source_revision": {
            "type": "integer",
            "minimum": 1,
            "description": "Orders only the tennis_points group for the same match. Never compare this with live_score.source_revision."
          },
          "observed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When 0xinsider observed these API-Tennis facts. This is not a timestamp from the court."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Stop displaying the point group at this instant, even if the enclosing score remains fresh. The group expires 30 seconds after observed_at."
          },
          "set_number": {
            "type": "integer",
            "minimum": 1,
            "description": "Current set number. Display points only while this matches the enclosing scoreboard, unless set_games is present."
          },
          "games": {
            "type": "array",
            "minItems": 2,
            "maxItems": 2,
            "items": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Current-set games in first/second order. Display points only while these match the enclosing scoreboard, unless set_games is present."
          },
          "set_games": {
            "type": "array",
            "items": {
              "type": "array",
              "minItems": 2,
              "maxItems": 2,
              "items": {
                "type": "integer",
                "minimum": 0
              }
            },
            "description": "API-Tennis games in every listed set, first set first, each in first/second order. Present only when Polymarket publishes no score for the match (tennis doubles): display these as the set score, and discard the group once live_score carries a nonzero game. A deciding match tie-break is listed as games, for example 9-5. Omitted for every other match."
          }
        }
      },
      "WebhookVerificationAttempt": {
        "type": "object",
        "required": [
          "id",
          "object",
          "webhook_id",
          "state",
          "outcome",
          "attempt_count",
          "max_attempts",
          "expires_at",
          "next_attempt_at",
          "last_response_status",
          "started_at",
          "completed_at",
          "created_at",
          "updated_at",
          "status_url"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "object": {
            "type": "string",
            "const": "webhook_verification_attempt"
          },
          "webhook_id": {
            "type": "integer",
            "format": "int64"
          },
          "state": {
            "type": "string",
            "enum": ["queued", "running", "verified", "failed", "cancelled", "expired"],
            "description": "queued/running are pending consent. verified means the same endpoint revision answered 2xx and activated atomically. failed/cancelled/expired are terminal and do not restart on polling or replay."
          },
          "outcome": {
            "type": ["string", "null"],
            "enum": [
              "verified",
              "target_rejected",
              "challenge_timeout",
              "transport_failed",
              "receiver_rejected",
              "token_expired",
              "endpoint_changed",
              "owner_revoked",
              "attempts_exhausted",
              "internal_error",
              null
            ],
            "description": "Sanitized last observation. Null before an observation; queued retries may retain their previous failure outcome."
          },
          "attempt_count": {
            "type": "integer",
            "minimum": 0,
            "maximum": 4
          },
          "max_attempts": {
            "type": "integer",
            "const": 4
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Earlier of the verification-token deadline and 15 minutes after admission. Activation is forbidden at or after this instant."
          },
          "next_attempt_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Scheduled retry/admission time while queued; null while running or terminal."
          },
          "last_response_status": {
            "type": ["integer", "null"],
            "minimum": 100,
            "maximum": 599,
            "description": "Actual receiver HTTP status, when one arrived. No receiver response body or resolved address is returned."
          },
          "started_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "completed_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "status_url": {
            "type": "string",
            "description": "Relative authorized API path for this attempt. Uses the same bearer credential as admission."
          }
        },
        "additionalProperties": false
      },
      "CreateWebhookVerificationAttemptRequest": {
        "type": "object",
        "required": ["verification_token"],
        "properties": {
          "verification_token": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "The original one-time token returned by webhook creation or a URL change. Sent only in the request body and signed receiver challenge."
          }
        },
        "additionalProperties": false
      },
      "PickOfTheDayNoEntitledPicks": {
        "type": "object",
        "description": "A successful current-day entitlement response when only unauthorized ranks have published. It carries an empty pick set, identity-free locked ranks and an upgrade message. Selection IDs, game identity, prices and unauthorized clocks are absent. Any scheduled or proof-pending rows are entitled rows.",
        "required": [
          "state",
          "pick_date",
          "picks",
          "pick_count",
          "locked_picks",
          "message",
          "supersedes_pick_id"
        ],
        "properties": {
          "state": {
            "type": "string",
            "enum": ["none"],
            "description": "Only locked ranks are published for this account."
          },
          "pick_date": {
            "type": "string",
            "format": "date",
            "description": "Current product date in America/New_York (YYYY-MM-DD)."
          },
          "picks": {
            "type": "array",
            "maxItems": 0,
            "items": {
              "$ref": "#/components/schemas/PickOfTheDay"
            },
            "description": "Empty: no entitled proof-readable picks are returned."
          },
          "pick_count": {
            "type": "integer",
            "const": 0,
            "description": "Zero entitled proof-readable picks."
          },
          "locked_picks": {
            "type": "array",
            "description": "Unauthorized unresolved published or scheduled ranks. Contains no game, provider identity, price, or identifying clock. Pro may upgrade to Max to open these ranks.",
            "items": {
              "type": "object",
              "required": ["pick_rank", "required_tier"],
              "properties": {
                "pick_rank": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 30
                },
                "required_tier": {
                  "type": "string",
                  "enum": ["max"]
                }
              }
            },
            "minItems": 1
          },
          "message": {
            "type": "string",
            "description": "Actionable status, including Upgrade to Max when only locked ranks are published."
          },
          "scheduled_picks": {
            "type": "array",
            "description": "Rank-ordered entitled selections that have not released. Every row retains release_at and kickoff; unauthorized scheduled ranks appear only in identity-free locked_picks.",
            "items": {
              "$ref": "#/components/schemas/ScheduledPickSlot"
            }
          },
          "supersedes_pick_id": {
            "deprecated": true,
            "type": ["string", "null"],
            "pattern": "^[1-9][0-9]*$",
            "description": "Deprecated (#24157): always null. No replacement lineage was ever recorded in this field; the key stays so existing V1 clients keep parsing. Identify a pick by pick_id."
          }
        }
      },
      "PickLeadBacker": {
        "type": "object",
        "description": "Recorded lead wallet facts on a full response when available. Position and category history are frozen at publication; they are not live balances or pick win probabilities.",
        "properties": {
          "address": {
            "type": "string",
            "description": "Lead trader wallet address."
          },
          "name": {
            "type": ["string", "null"],
            "description": "Recorded provider display name."
          },
          "grade": {
            "type": "string",
            "description": "Trader grade recorded at publication."
          },
          "category": {
            "type": "string",
            "description": "Canonical sport of the recorded directional history."
          },
          "position_usd": {
            "type": "number",
            "description": "Provider-reported position value on the backed outcome at publication, in USD. It is the gross value on that outcome and does not subtract shares the wallet held on the other outcome; see net_position_usd. It is not the entry cost or a live balance."
          },
          "net_position_usd": {
            "type": "number",
            "description": "Net value of the lead's position toward the backed outcome at publication, in USD: shares held on the backed outcome minus shares held on the other outcome of the same market, valued at the backed outcome's provider price at publication. Present only when the wallet also held the other outcome; absent for a one-sided position, whose net equals position_usd. It is not a live balance."
          },
          "position_observed_at": {
            "type": "string",
            "format": "date-time",
            "description": "Start time of the provider position fetch used at publication. This conservative observation clock precedes completion; the position is not a live balance."
          },
          "directional_event_count": {
            "type": "integer",
            "description": "Distinct directional events in the recorded category history."
          },
          "profitable_event_count": {
            "type": "integer",
            "minimum": 0,
            "maximum": 4294967295,
            "description": "Events with strictly positive native terminal P&L in the same frozen category sample as directional_event_count, realized_pnl_usd and roi. Multiple market positions in one event contribute one combined event result. Zero-profit events remain in directional_event_count but do not increase this count. This is a recorded wallet result, not a market win rate or the pick's win probability."
          },
          "realized_pnl_usd": {
            "type": "number",
            "description": "Realized P&L over the recorded directional category sample, in USD. Excludes open positions and later changes."
          },
          "entry_basis_usd": {
            "type": "number",
            "description": "Recorded entry basis of that directional sample, in USD; not a claim of complete trading costs or fees."
          },
          "roi": {
            "type": "number",
            "description": "Realized P&L divided by recorded entry basis, as a fraction: 0.10 means 10%. This is a wallet statistic, not a pick win probability."
          },
          "max_realized_drawdown_usd": {
            "type": "number",
            "description": "Peak-to-trough realized P&L drawdown after each event result in the recorded sample, in USD. Excludes intragame, unrealized, and account equity drawdown."
          },
          "recorded_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the directional history evidence was recorded, separate from the provider position snapshot clock."
          }
        },
        "required": [
          "address",
          "name",
          "grade",
          "category",
          "position_usd",
          "position_observed_at",
          "directional_event_count",
          "profitable_event_count",
          "realized_pnl_usd",
          "entry_basis_usd",
          "roi",
          "max_realized_drawdown_usd",
          "recorded_at"
        ]
      },
      "TennisRanking": {
        "type": "object",
        "description": "A provider-reported ATP/WTA singles rank with independent retrieval and expiry clocks. API-Tennis provides no ranking publication date. Retrieval time does not establish when the tour published the ranking.",
        "required": ["rank", "tour", "source", "observed_at", "expires_at"],
        "additionalProperties": false,
        "properties": {
          "rank": {
            "type": "integer",
            "minimum": 1,
            "maximum": 4294967295,
            "description": "Provider-reported singles rank."
          },
          "tour": {
            "type": "string",
            "enum": ["atp", "wta"],
            "description": "The player ranking tour."
          },
          "source": {
            "type": "string",
            "enum": ["api_tennis"],
            "description": "The standings provider."
          },
          "observed_at": {
            "type": "string",
            "format": "date-time",
            "description": "Successful snapshot retrieval time in UTC, not ranking publication date."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "UTC deadline after which clients must hide this rank, including when an older game or pick response remains cached."
          }
        }
      },
      "ComboLegMarket": {
        "type": "object",
        "required": [
          "source",
          "condition_id",
          "title",
          "slug",
          "event_slug",
          "outcome_label",
          "image",
          "category",
          "winning_outcome",
          "resolved_at",
          "market_closed",
          "pick_price_daily",
          "pick_price_as_of",
          "pick_price_age_days",
          "provider_leg_status"
        ],
        "properties": {
          "source": {
            "type": "string",
            "description": "Source of the leg facts.",
            "enum": ["markets", "provider"]
          },
          "condition_id": {
            "type": "string",
            "description": "Full binary CTF condition ID for this leg."
          },
          "title": {
            "type": ["string", "null"]
          },
          "slug": {
            "type": ["string", "null"]
          },
          "event_slug": {
            "type": ["string", "null"]
          },
          "polymarket_url": {
            "type": "string",
            "description": "Provider-resolved URL including the referral tag.",
            "format": "uri"
          },
          "outcome_label": {
            "type": ["string", "null"]
          },
          "image": {
            "type": ["string", "null"]
          },
          "category": {
            "type": ["string", "null"]
          },
          "winning_outcome": {
            "type": ["integer", "null"],
            "format": "int64",
            "description": "Provider outcome index; negative sentinels describe void or unresolved states."
          },
          "resolved_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "market_closed": {
            "type": ["boolean", "null"],
            "description": "A closed market may still have no terminal outcome."
          },
          "pick_price_daily": {
            "type": ["number", "null"],
            "description": "Stored daily price for this leg outcome token; not a live quote."
          },
          "pick_price_as_of": {
            "type": ["string", "null"],
            "description": "Observation time of the stored daily price.",
            "format": "date-time"
          },
          "pick_price_age_days": {
            "type": ["integer", "null"],
            "format": "int64",
            "description": "Whole days since the stored daily bucket."
          },
          "provider_leg_status": {
            "type": ["string", "null"],
            "description": "Unmodified provider leg status when available."
          }
        }
      },
      "ComboLeg": {
        "type": "object",
        "required": ["leg_index", "outcome_index", "module_id", "state", "market"],
        "properties": {
          "leg_index": {
            "type": "integer",
            "format": "int64"
          },
          "outcome_index": {
            "type": "integer",
            "format": "int64"
          },
          "module_id": {
            "type": "integer",
            "format": "int64"
          },
          "state": {
            "type": "string",
            "enum": ["pending", "won", "lost", "void", "unknown"]
          },
          "market": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ComboLegMarket"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "ComboWindowStats": {
        "type": "object",
        "required": ["fills", "volume_usdc", "distinct_traders", "largest_fill_usdc"],
        "properties": {
          "fills": {
            "type": "integer",
            "format": "int64"
          },
          "volume_usdc": {
            "type": "string",
            "description": "Exact decimal string from the stored chain or SQL value; preserve precision until display."
          },
          "distinct_traders": {
            "type": "integer",
            "format": "int64"
          },
          "largest_fill_usdc": {
            "type": "string",
            "description": "Exact decimal string from the stored chain or SQL value; preserve precision until display."
          }
        }
      },
      "ComboTotals": {
        "type": "object",
        "required": [
          "fills",
          "volume_usdc",
          "largest_fill_usdc",
          "first_fill_at",
          "last_fill_at",
          "last_fill_price_yes",
          "last_fill_outcome_index",
          "last_fill_action"
        ],
        "properties": {
          "fills": {
            "type": "integer",
            "format": "int64"
          },
          "volume_usdc": {
            "type": "string",
            "description": "Exact decimal string from the stored chain or SQL value; preserve precision until display."
          },
          "largest_fill_usdc": {
            "type": "string",
            "description": "Exact decimal string from the stored chain or SQL value; preserve precision until display."
          },
          "first_fill_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_fill_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_fill_price_yes": {
            "type": ["string", "null"],
            "description": "Last taker execution normalized to YES; not a current quote."
          },
          "last_fill_outcome_index": {
            "type": "integer",
            "format": "int64"
          },
          "last_fill_action": {
            "type": "string",
            "enum": ["buy", "sell"]
          }
        }
      },
      "Combo": {
        "type": "object",
        "required": [
          "condition_id",
          "leg_count",
          "prepared_at",
          "legs_known",
          "legs",
          "window",
          "totals",
          "status",
          "status_reason"
        ],
        "properties": {
          "condition_id": {
            "type": "string",
            "description": "Combo identifier: 0x followed by 62 lowercase hex characters. This differs from a binary market condition ID.",
            "pattern": "^0x[0-9a-f]{62}$"
          },
          "leg_count": {
            "type": ["integer", "null"],
            "format": "int64"
          },
          "prepared_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "legs_known": {
            "type": "boolean",
            "description": "Whether the preparation event has been indexed."
          },
          "legs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ComboLeg"
            }
          },
          "window": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ComboWindowStats"
              },
              {
                "type": "null"
              }
            ]
          },
          "totals": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ComboTotals"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "type": "string",
            "description": "Result of the YES conjunction, independent of the wallet side or its P&L.",
            "enum": ["pending", "won", "lost", "unknown"]
          },
          "status_reason": {
            "type": ["string", "null"],
            "description": "Reason the conjunction result cannot be verified, when unknown."
          }
        }
      },
      "ComboCoverageCursor": {
        "type": "object",
        "required": [
          "contract",
          "last_block",
          "seed_block",
          "seed_origin",
          "chain_finalized_block",
          "lag_blocks",
          "updated_at"
        ],
        "properties": {
          "contract": {
            "type": "string",
            "description": "Indexed contract."
          },
          "last_block": {
            "type": "integer",
            "format": "int64"
          },
          "seed_block": {
            "type": "integer",
            "format": "int64"
          },
          "seed_origin": {
            "type": "string"
          },
          "chain_finalized_block": {
            "type": ["integer", "null"],
            "format": "int64"
          },
          "lag_blocks": {
            "type": ["integer", "null"],
            "format": "int64"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ComboCoverage": {
        "type": "object",
        "required": [
          "state",
          "ingest_enabled",
          "cursors",
          "max_lag_blocks",
          "oldest_cursor_update",
          "lifecycle_lag_blocks",
          "lifecycle_backfilling",
          "computed_at"
        ],
        "properties": {
          "state": {
            "type": "string",
            "enum": ["paused", "uninitialized", "stale", "backfilling", "live"]
          },
          "ingest_enabled": {
            "type": "boolean"
          },
          "cursors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ComboCoverageCursor"
            }
          },
          "max_lag_blocks": {
            "type": ["integer", "null"],
            "format": "int64"
          },
          "oldest_cursor_update": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "lifecycle_lag_blocks": {
            "type": ["integer", "null"],
            "format": "int64"
          },
          "lifecycle_backfilling": {
            "type": "boolean"
          },
          "computed_at": {
            "type": "string",
            "description": "Time the coverage state was evaluated; not a market-price timestamp.",
            "format": "date-time"
          }
        }
      },
      "ComboFill": {
        "type": "object",
        "required": [
          "id",
          "block_number",
          "log_index",
          "block_timestamp",
          "tx_hash",
          "trader",
          "trader_name",
          "trader_grade",
          "last_traded_at",
          "action",
          "condition_id",
          "outcome_index",
          "shares",
          "collateral_usdc",
          "price",
          "price_yes",
          "fee_usdc",
          "leg_count",
          "status",
          "status_reason",
          "won_legs",
          "payout_multiplier",
          "legs"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable fill identity."
          },
          "block_number": {
            "type": "integer",
            "format": "int64"
          },
          "log_index": {
            "type": "integer",
            "format": "int64"
          },
          "block_timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "tx_hash": {
            "type": "string"
          },
          "trader": {
            "type": ["string", "null"],
            "description": "Taker wallet address."
          },
          "trader_name": {
            "type": ["string", "null"]
          },
          "trader_grade": {
            "type": ["string", "null"],
            "enum": ["S", "A", "B", "C", "D", "F", null]
          },
          "last_traded_at": {
            "type": ["string", "null"],
            "description": "Recorded wallet-wide trade time.",
            "format": "date-time"
          },
          "action": {
            "type": "string",
            "enum": ["buy", "sell"]
          },
          "condition_id": {
            "type": "string",
            "description": "Combo identifier: 0x followed by 62 lowercase hex characters. This differs from a binary market condition ID.",
            "pattern": "^0x[0-9a-f]{62}$"
          },
          "outcome_index": {
            "type": "integer",
            "format": "int64",
            "description": "0 is YES, 1 is NO."
          },
          "shares": {
            "type": "string",
            "description": "Exact decimal string from the stored chain or SQL value; preserve precision until display."
          },
          "collateral_usdc": {
            "type": "string",
            "description": "Exact decimal string from the stored chain or SQL value; preserve precision until display."
          },
          "price": {
            "type": ["string", "null"],
            "description": "Execution price for the traded outcome; null for a zero-share event."
          },
          "price_yes": {
            "type": ["string", "null"],
            "description": "Execution price normalized to YES."
          },
          "fee_usdc": {
            "type": "string",
            "description": "Exact decimal string from the stored chain or SQL value; preserve precision until display."
          },
          "leg_count": {
            "type": ["integer", "null"],
            "format": "int64"
          },
          "status": {
            "type": "string",
            "description": "Result of the YES conjunction, independent of the wallet side or its P&L.",
            "enum": ["pending", "won", "lost", "unknown"]
          },
          "status_reason": {
            "type": ["string", "null"]
          },
          "won_legs": {
            "type": "integer",
            "format": "int64"
          },
          "payout_multiplier": {
            "type": ["string", "null"],
            "description": "Shares per dollar at execution; not a forecast or guaranteed return."
          },
          "legs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ComboLeg"
            }
          }
        }
      },
      "ComboLifecycleStats": {
        "type": "object",
        "required": [
          "splits",
          "merges",
          "redeems",
          "compresses",
          "split_usdc",
          "merge_usdc",
          "redeemed_shares",
          "redeemed_usdc",
          "compressed_usdc",
          "last_event_at"
        ],
        "properties": {
          "splits": {
            "type": "integer",
            "format": "int64"
          },
          "merges": {
            "type": "integer",
            "format": "int64"
          },
          "redeems": {
            "type": "integer",
            "format": "int64"
          },
          "compresses": {
            "type": "integer",
            "format": "int64"
          },
          "split_usdc": {
            "type": "string",
            "description": "Exact decimal string from the stored chain or SQL value; preserve precision until display."
          },
          "merge_usdc": {
            "type": "string",
            "description": "Exact decimal string from the stored chain or SQL value; preserve precision until display."
          },
          "redeemed_shares": {
            "type": "string",
            "description": "Exact decimal string from the stored chain or SQL value; preserve precision until display."
          },
          "redeemed_usdc": {
            "type": "string",
            "description": "Exact decimal string from the stored chain or SQL value; preserve precision until display."
          },
          "compressed_usdc": {
            "type": "string",
            "description": "Exact decimal string from the stored chain or SQL value; preserve precision until display."
          },
          "last_event_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ComboDetail": {
        "type": "object",
        "required": ["access", "combo", "fills", "lifecycle", "coverage"],
        "properties": {
          "access": {
            "type": "string",
            "enum": ["full"],
            "x-narrowed": true
          },
          "combo": {
            "$ref": "#/components/schemas/Combo"
          },
          "fills": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/ComboFill"
            }
          },
          "lifecycle": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ComboLifecycleStats"
              },
              {
                "type": "null"
              }
            ]
          },
          "coverage": {
            "$ref": "#/components/schemas/ComboCoverage"
          }
        },
        "description": "One combo with its newest 100 fills and all-time lifecycle totals. Paid API callers receive full access."
      },
      "ComboLiveCount": {
        "type": "object",
        "required": ["count", "computed_at"],
        "properties": {
          "count": {
            "type": "integer",
            "format": "int64",
            "description": "Traded combos whose YES conjunction remains pending."
          },
          "computed_at": {
            "type": "string",
            "description": "Time the count was computed; check its age before using it.",
            "format": "date-time"
          }
        }
      },
      "CombosSummary": {
        "type": "object",
        "required": ["live"],
        "properties": {
          "live": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ComboLiveCount"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "description": "Stored live combo count. Null means the first count is unavailable, never zero."
      },
      "ComboFillsResponse": {
        "type": "object",
        "required": ["object", "data", "sort", "window", "limit", "coverage", "has_more", "meta"],
        "properties": {
          "object": {
            "type": "string",
            "const": "list"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ComboFill"
            }
          },
          "sort": {
            "type": "string",
            "enum": ["recent", "largest", "payout"]
          },
          "window": {
            "type": "string",
            "enum": ["24h", "7d", "all"]
          },
          "limit": {
            "type": "integer",
            "format": "int64"
          },
          "coverage": {
            "$ref": "#/components/schemas/ComboCoverage"
          },
          "has_more": {
            "type": "boolean",
            "description": "A continuation is available based on page fullness. Its next page may be empty."
          },
          "next_cursor": {
            "type": "string",
            "description": "Exclusive block_number:log_index continuation for recent ordering."
          },
          "next_offset": {
            "type": "integer",
            "format": "int64",
            "description": "Continuation offset for largest or payout ordering."
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        }
      },
      "ComboResponse": {
        "type": "object",
        "required": ["object", "data", "meta"],
        "properties": {
          "object": {
            "type": "string",
            "const": "combo"
          },
          "data": {
            "$ref": "#/components/schemas/ComboDetail"
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        }
      },
      "CombosSummaryResponse": {
        "type": "object",
        "required": ["object", "data", "meta"],
        "properties": {
          "object": {
            "type": "string",
            "const": "combos_summary"
          },
          "data": {
            "$ref": "#/components/schemas/CombosSummary"
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        }
      },
      "EdgeHunterPrice": {
        "type": "object",
        "required": ["price", "basis", "ts"],
        "properties": {
          "price": {
            "type": "string",
            "description": "Provider probability as a decimal string. Keep its precision until display."
          },
          "basis": {
            "type": "string",
            "enum": ["midpoint", "last_trade"]
          },
          "ts": {
            "type": "string",
            "description": "Source observation clock in epoch milliseconds, represented as a string."
          },
          "validated_at": {
            "type": "string",
            "description": "Backend validation clock in epoch milliseconds. Omitted when no current-source validation is available."
          }
        }
      },
      "EdgeHunterParticipant": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "provider_id": {
            "type": "integer",
            "format": "int64"
          },
          "logo": {
            "type": "string"
          },
          "logo_mark_dark": {
            "type": "boolean"
          },
          "color": {
            "type": "string"
          },
          "headshot": {
            "type": "string"
          },
          "headshot_revision": {
            "type": "integer",
            "format": "int64"
          },
          "tour": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "logo_mark_light": {
            "type": "boolean"
          },
          "logo_mark_measured": {
            "type": "boolean"
          }
        }
      },
      "EdgeHunterOutcome": {
        "type": "object",
        "required": ["index", "label", "provider_id", "token_id", "current_price"],
        "properties": {
          "index": {
            "type": "integer",
            "enum": [0, 1]
          },
          "label": {
            "type": ["string", "null"]
          },
          "provider_id": {
            "type": ["integer", "null"],
            "format": "int64"
          },
          "token_id": {
            "type": ["string", "null"],
            "description": "Frozen provider CLOB token ID for this exact outcome in YES/NO order. Null when unavailable; not a participant identity.",
            "example": "5100000000000000000000000000000000000000000000000000000000000000001"
          },
          "current_price": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EdgeHunterPrice"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "description": "One provider outcome in fixed YES/NO order, including its frozen token identity and independently observed quote. Null current_price means no verified current quote is available."
      },
      "EdgeHunterSignal": {
        "type": "object",
        "required": [
          "piled_side",
          "piled_outcome_index",
          "sharp_pct",
          "backed_sharp_usd",
          "s_count",
          "a_count",
          "b_count",
          "graded_holders",
          "top_grade",
          "smart_score",
          "net_side",
          "conviction_score",
          "one_way_holder_count",
          "hedged_holder_count",
          "one_way_graded_usd",
          "directional_confidence",
          "directional_rank_score",
          "current_price",
          "token_id",
          "ranked_at",
          "category_skill"
        ],
        "properties": {
          "piled_side": {
            "type": ["string", "null"]
          },
          "piled_outcome_index": {
            "type": "integer",
            "enum": [0, 1]
          },
          "sharp_pct": {
            "type": ["number", "null"],
            "minimum": 0,
            "maximum": 1,
            "description": "Fraction of graded money on the backed side, not a percentage from 0 to 100."
          },
          "backed_sharp_usd": {
            "type": "number"
          },
          "s_count": {
            "type": "integer"
          },
          "a_count": {
            "type": "integer"
          },
          "b_count": {
            "type": "integer"
          },
          "graded_holders": {
            "type": "integer"
          },
          "top_grade": {
            "type": ["string", "null"],
            "enum": ["S", "A", "B", null]
          },
          "smart_score": {
            "type": ["number", "null"]
          },
          "net_side": {
            "type": ["string", "null"]
          },
          "conviction_score": {
            "type": "number"
          },
          "one_way_holder_count": {
            "type": ["integer", "null"]
          },
          "hedged_holder_count": {
            "type": ["integer", "null"]
          },
          "one_way_graded_usd": {
            "type": ["number", "null"]
          },
          "directional_confidence": {
            "type": ["number", "null"]
          },
          "directional_rank_score": {
            "type": "number"
          },
          "current_price": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EdgeHunterPrice"
              },
              {
                "type": "null"
              }
            ]
          },
          "token_id": {
            "type": ["string", "null"],
            "description": "Frozen provider CLOB token ID for the backed outcome. Null when unavailable; matches outcomes[piled_outcome_index].token_id when the shared provider context is available.",
            "example": "5100000000000000000000000000000000000000000000000000000000000000001"
          },
          "ranked_at": {
            "type": "string",
            "format": "date-time",
            "description": "UTC computation time copied from this ranked row's frozen signal_created_at. It dates the ranking, not the separately observed quote, metadata writer, or wallet entry.",
            "example": "2026-10-11T18:00:00Z"
          },
          "category_skill": {
            "$ref": "#/components/schemas/EdgeHunterCategorySkill",
            "description": "Existing aggregate category evidence copied from the same ranked snapshot. Read its status, coverage and own clocks; it never changes admission or ordering and is not a predicted return."
          }
        },
        "description": "Backed-side analytics, token identity, frozen ranked_at and aggregate category evidence from the ranked snapshot, plus a separately dated current quote. Scores rank attention; they are not probabilities or order instructions."
      },
      "EdgeHunterRow": {
        "type": "object",
        "required": [
          "rank",
          "state",
          "free",
          "condition_id",
          "event_slug",
          "title",
          "category",
          "raw_category",
          "game_start_time",
          "volume",
          "participants",
          "image",
          "outcomes",
          "signal",
          "market_context"
        ],
        "properties": {
          "rank": {
            "type": "integer",
            "minimum": 1
          },
          "state": {
            "type": "string",
            "const": "full",
            "x-narrowed": true
          },
          "free": {
            "type": "boolean",
            "const": false
          },
          "condition_id": {
            "type": "string"
          },
          "event_slug": {
            "type": ["string", "null"]
          },
          "title": {
            "type": ["string", "null"]
          },
          "category": {
            "type": ["string", "null"],
            "enum": [
              "Basketball",
              "Football",
              "Baseball",
              "Hockey",
              "MMA",
              "Boxing",
              "Soccer",
              "Cricket",
              "Golf",
              "Tennis",
              "Esports",
              "Racing",
              "Table Tennis",
              "Pickleball",
              null
            ]
          },
          "raw_category": {
            "type": ["string", "null"]
          },
          "game_start_time": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "volume": {
            "type": ["number", "null"],
            "description": "Cumulative provider taker volume in shares, not cash in USD. Null when unavailable."
          },
          "participants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EdgeHunterParticipant"
            }
          },
          "image": {
            "type": ["string", "null"]
          },
          "outcomes": {
            "type": "array",
            "minItems": 2,
            "maxItems": 2,
            "items": {
              "$ref": "#/components/schemas/EdgeHunterOutcome"
            }
          },
          "signal": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EdgeHunterSignal"
              },
              {
                "type": "null"
              }
            ]
          },
          "market_context": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EdgeHunterMarketContext"
              },
              {
                "type": "null"
              }
            ],
            "description": "Required nullable frozen metadata context. Null only during the legacy-generation transition; selected reads require sidecar readiness and fail closed with 503 instead."
          }
        },
        "description": "One full Max row from Edge Hunter. signal is populated on every row this endpoint returns. Identity and quotes preserve provider values; unknown values stay null."
      },
      "EdgeHunterBoard": {
        "type": "object",
        "required": [
          "as_of",
          "horizon_hours",
          "min_grade",
          "ranking_source",
          "directional_source",
          "cached_age_seconds",
          "viewer",
          "free_rank",
          "total",
          "rows"
        ],
        "properties": {
          "as_of": {
            "type": "string",
            "format": "date-time",
            "description": "When the ranked snapshot was computed. Date current quotes with their own ts values."
          },
          "horizon_hours": {
            "type": "integer",
            "minimum": 1,
            "maximum": 48
          },
          "min_grade": {
            "type": "string",
            "enum": ["S", "A", "B"],
            "default": "B",
            "description": "Requested holder-presence grade floor, S/A/B. A holder at that grade or better admits the row; other holders remain visible."
          },
          "ranking_source": {
            "type": "string",
            "enum": ["live", "db_only"],
            "description": "live uses the current graded holder pile; db_only is a weaker stored-data fallback."
          },
          "directional_source": {
            "type": "string",
            "enum": ["live", "degraded"],
            "description": "degraded means directional enrichment was unavailable."
          },
          "cached_age_seconds": {
            "type": ["integer", "null"],
            "minimum": 0
          },
          "viewer": {
            "type": "string",
            "const": "max",
            "x-narrowed": true
          },
          "free_rank": {
            "type": ["integer", "null"],
            "description": "Always null: Edge Hunter has no free signal slot."
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "Ranked rows after normalized selections and grade filtering, before the view-specific limit cap."
          },
          "rows": {
            "type": "array",
            "maxItems": 30,
            "items": {
              "$ref": "#/components/schemas/EdgeHunterRow"
            }
          }
        },
        "description": "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."
      },
      "EdgeHunterRankedSignal": {
        "type": "object",
        "description": "One ranked pre-game sports market where graded sharp money is piled on one side, with required-status category evidence from partial forward-observed Polymarket fills.",
        "required": [
          "condition_id",
          "signal_created_at",
          "token_id",
          "category",
          "raw_category",
          "title",
          "event_slug",
          "game_start_time",
          "piled_side",
          "piled_outcome_index",
          "sharp_pct",
          "backed_sharp_usd",
          "s_count",
          "a_count",
          "b_count",
          "graded_holders",
          "top_grade",
          "smart_score",
          "volume",
          "net_side",
          "conviction_score",
          "one_way_holder_count",
          "hedged_holder_count",
          "one_way_graded_usd",
          "directional_confidence",
          "directional_rank_score",
          "category_skill",
          "rank",
          "side",
          "ranked_at",
          "backing_score",
          "side_share",
          "market_context"
        ],
        "properties": {
          "side": {
            "type": ["string", "null"],
            "description": "The side profitable wallets hold, as a provider-backed display label. Canonical spelling of piled_side (#16310), same value: when provider group context is unavailable it may remain a bare Yes/No/Over/Under, so do not use it alone as participant identity."
          },
          "ranked_at": {
            "type": "string",
            "format": "date-time",
            "description": "UTC time at which the snapshot that ranked this row was computed. Canonical spelling of signal_created_at (#16310), same value."
          },
          "backing_score": {
            "type": "number",
            "description": "Recorded side backing score; higher values indicate stronger backing."
          },
          "side_share": {
            "type": ["number", "null"],
            "description": "Signed share of graded money on the side, (yes_usd - no_usd)/(yes_usd + no_usd) in [-1, 1] (side-yes positive, side-no negative). Canonical spelling of smart_score (#16309, #16310), same value."
          },
          "condition_id": {
            "type": "string",
            "description": "Polymarket condition id."
          },
          "signal_created_at": {
            "deprecated": true,
            "type": "string",
            "format": "date-time",
            "description": "UTC time at which the immutable signal snapshot was computed. Every row from one snapshot shares this value; it is not provider market creation time and is not rewritten at request time. Deprecated (#16310): `ranked_at` is the canonical spelling and carries the same value; this key stays on the wire."
          },
          "token_id": {
            "type": ["string", "null"],
            "description": "Polymarket CLOB token id (ERC1155 asset id, decimal string) for the PILED outcome; null when unavailable."
          },
          "category": {
            "type": ["string", "null"],
            "description": "Canonical sport bucket (e.g. Basketball, Tennis); null when the raw category has no canonical mapping.",
            "enum": [
              "Basketball",
              "Football",
              "Baseball",
              "Hockey",
              "MMA",
              "Boxing",
              "Soccer",
              "Cricket",
              "Golf",
              "Tennis",
              "Esports",
              "Racing",
              "Table Tennis",
              "Pickleball",
              null
            ]
          },
          "raw_category": {
            "type": ["string", "null"],
            "description": "Raw provider category as stored (e.g. NBA, EPL)."
          },
          "title": {
            "type": ["string", "null"]
          },
          "event_slug": {
            "type": ["string", "null"]
          },
          "game_start_time": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Kickoff (UTC). In the future at SNAPSHOT time and within the requested horizon; because the response is served from a shared snapshot cached up to the ~180s TTL, a served kickoff can be up to ~180s in the past relative to the response time. Not a live guarantee that the game has not yet started."
          },
          "piled_side": {
            "deprecated": true,
            "type": ["string", "null"],
            "description": "Nullable provider-backed piled-outcome display label. When provider group context is unavailable, it may remain a bare Yes/No/Over/Under; do not use it alone as participant identity. Deprecated (#16310): `side` is the canonical spelling and carries the same value; this key stays on the wire."
          },
          "piled_outcome_index": {
            "type": "integer",
            "description": "Provider binary-column selector: 0 selects outcome_yes/token_id_yes; 1 selects outcome_no/token_id_no. It does not identify home/away or a participant. Use piled_side together with title/event context for display."
          },
          "sharp_pct": {
            "type": ["number", "null"],
            "description": "Piled-side dollar concentration backed_usd / (yes_usd + no_usd), in (0.5, 1] for a real pile; null when there is no sharp USD."
          },
          "backed_sharp_usd": {
            "type": "number",
            "description": "Raw piled-side sharp-money USD."
          },
          "s_count": {
            "type": "integer",
            "description": "S-grade graded holders on the piled side."
          },
          "a_count": {
            "type": "integer",
            "description": "A-grade graded holders on the piled side."
          },
          "b_count": {
            "type": "integer",
            "description": "B-grade graded holders on the piled side."
          },
          "graded_holders": {
            "type": "integer",
            "description": "Piled-side graded holder count (s_count + a_count + b_count)."
          },
          "top_grade": {
            "type": ["string", "null"],
            "enum": ["S", "A", "B", null],
            "description": "Best grade present on the piled side; null when none."
          },
          "smart_score": {
            "deprecated": true,
            "type": ["number", "null"],
            "description": "Canonical sharp-money score (yes_usd - no_usd)/(yes_usd + no_usd) in [-1, 1] (piled-yes positive, piled-no negative). Deprecated (#16310): `side_share` is the canonical spelling and carries the same value; this key stays on the wire."
          },
          "volume": {
            "type": ["number", "null"],
            "description": "Cumulative provider taker volume in shares, not cash or dollars."
          },
          "net_side": {
            "type": ["string", "null"],
            "enum": ["BUY", "SELL", null],
            "description": "Aggregate recent flow direction on the market; null when unavailable."
          },
          "conviction_score": {
            "deprecated": true,
            "type": "number",
            "description": "Recorded conviction score; higher values indicate stronger conviction."
          },
          "one_way_holder_count": {
            "type": ["integer", "null"],
            "description": "Piled-side graded holders read one-way: their fresh open legs across the signal game's markets (cross-market within the one game; moneyline+spread family only) all back the same team, or, when the market's holder scan was complete, Polymarket's currentValue shows no opposite leg on this market worth 10% of the backed leg and no fresh leg opposes it. Null when the directional read was not computed (no groupable game, no holder-level data on this ranking path, or the enrichment read failed) or classified nobody."
          },
          "hedged_holder_count": {
            "type": ["integer", "null"],
            "description": "Piled-side graded holders classified HEDGED across the game by fresh legs (they back two or more distinct teams). A wallet long both outcomes of this market is not one-way and not counted here. Null when the directional read was not computed or classified nobody."
          },
          "one_way_graded_usd": {
            "type": ["number", "null"],
            "description": "Piled-side graded USD held by one-way wallets (share-weighted allocation of backed_sharp_usd). Null when the directional read was not computed or classified nobody."
          },
          "directional_confidence": {
            "type": ["number", "null"],
            "description": "One-way fraction of the piled graded dollars, in [0, 1] -- the metric orthogonal to sharp_pct. Stale, unknown, hedged, and two-sided dollars dilute it toward zero (conservative). Null when the directional read was not computed or classified nobody."
          },
          "directional_rank_score": {
            "type": "number",
            "description": "Recorded side ordering score; higher values sort first."
          },
          "category_skill": {
            "$ref": "#/components/schemas/EdgeHunterCategorySkill"
          },
          "rank": {
            "type": "integer",
            "description": "1-based rank within the (min_grade-filtered) ranked result."
          },
          "market_context": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EdgeHunterMarketContext"
              },
              {
                "type": "null"
              }
            ],
            "description": "Required nullable frozen metadata context. Null only during the legacy-generation transition; selected reads require sidecar readiness and fail closed with 503 instead."
          }
        }
      },
      "EdgeHunterCategorySkill": {
        "type": "object",
        "description": "Category evidence over the full uncapped piled-side S/A/B holder allocation. It never changes signal membership, ordering, routing, or sizing.",
        "required": [
          "status",
          "model_version",
          "taxonomy_version",
          "platform",
          "scope",
          "source_coverage",
          "observation_started_at",
          "as_of",
          "canonical_category",
          "eligible_holders",
          "covered_holders",
          "backed_sharp_usd",
          "covered_backed_usd",
          "coverage_pct",
          "weighted_edge_mean",
          "weighted_holder_lower_mean",
          "specialist_backed_usd",
          "specialist_backed_usd_pct",
          "largest_holder_backed_usd_pct",
          "minimum_holder_event_count"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["live", "insufficient", "stale", "unknown", "degraded"]
          },
          "model_version": {
            "type": "string"
          },
          "taxonomy_version": {
            "type": ["string", "null"]
          },
          "platform": {
            "type": "string",
            "const": "polymarket"
          },
          "scope": {
            "type": "string",
            "const": "observed_goldsky_primary_taker_fill"
          },
          "source_coverage": {
            "type": "string",
            "enum": ["partial_whale_threshold_fills", "graded_wallet_fills"]
          },
          "observation_started_at": {
            "type": "string",
            "format": "date-time"
          },
          "as_of": {
            "type": "string",
            "format": "date-time"
          },
          "canonical_category": {
            "type": ["string", "null"]
          },
          "eligible_holders": {
            "type": "integer",
            "minimum": 0
          },
          "covered_holders": {
            "type": "integer",
            "minimum": 0
          },
          "backed_sharp_usd": {
            "type": ["number", "null"],
            "minimum": 0
          },
          "covered_backed_usd": {
            "type": ["number", "null"],
            "minimum": 0
          },
          "coverage_pct": {
            "type": ["number", "null"],
            "minimum": 0,
            "maximum": 1
          },
          "weighted_edge_mean": {
            "type": ["number", "null"],
            "minimum": -1,
            "maximum": 1
          },
          "weighted_holder_lower_mean": {
            "type": ["number", "null"]
          },
          "specialist_backed_usd": {
            "type": ["number", "null"],
            "minimum": 0
          },
          "specialist_backed_usd_pct": {
            "type": ["number", "null"],
            "minimum": 0,
            "maximum": 1
          },
          "largest_holder_backed_usd_pct": {
            "type": ["number", "null"],
            "minimum": 0,
            "maximum": 1
          },
          "minimum_holder_event_count": {
            "type": ["integer", "null"],
            "minimum": 0
          }
        }
      },
      "EdgeHunterObservation": {
        "type": "object",
        "description": "One explicitly observation-only holder-pile measurement. It is evidence for cohort evaluation, not an execution instruction, and is isolated from the funded Edge Hunter signals view.",
        "required": [
          "condition_id",
          "token_id",
          "category",
          "raw_category",
          "title",
          "event_slug",
          "event_id",
          "parent_event_id",
          "game_start_time",
          "observed_at",
          "cohort",
          "admitted_by",
          "observation_only",
          "piled_side",
          "piled_outcome_index",
          "backed_price",
          "sharp_pct",
          "backed_sharp_usd",
          "s_count",
          "a_count",
          "b_count",
          "graded_holders",
          "top_grade",
          "smart_score",
          "volume",
          "conviction_score",
          "provider_read_source",
          "holder_scan_complete",
          "holder_snapshot_at",
          "directional_status",
          "one_way_holder_count",
          "hedged_holder_count",
          "one_way_graded_usd",
          "directional_confidence",
          "directional_rank_score",
          "rank",
          "side",
          "backing_score",
          "side_share",
          "market_context"
        ],
        "properties": {
          "side": {
            "type": ["string", "null"],
            "description": "The side profitable wallets hold, as a provider-backed display label. Canonical spelling of piled_side (#16310), same value: when provider group context is unavailable it may remain a bare Yes/No/Over/Under, so do not use it alone as participant identity."
          },
          "backing_score": {
            "type": "number",
            "minimum": 0,
            "description": "Recorded side backing score; higher values indicate stronger backing."
          },
          "side_share": {
            "type": "number",
            "minimum": -1,
            "maximum": 1,
            "description": "Signed share of graded money on the side, in [-1, 1]. Canonical spelling of smart_score (#16309, #16310), same value."
          },
          "condition_id": {
            "type": "string",
            "description": "Raw Polymarket condition id."
          },
          "token_id": {
            "type": "string",
            "description": "Provider-backed Polymarket CLOB token id for the piled outcome. Rows without a verified token terminate before emission."
          },
          "category": {
            "type": "string",
            "enum": [
              "Basketball",
              "Football",
              "Baseball",
              "Hockey",
              "MMA",
              "Boxing",
              "Soccer",
              "Cricket",
              "Golf",
              "Tennis",
              "Esports",
              "Racing",
              "Table Tennis",
              "Pickleball"
            ],
            "description": "Canonical sport bucket."
          },
          "raw_category": {
            "type": ["string", "null"],
            "description": "Raw provider category as stored."
          },
          "title": {
            "type": "string",
            "description": "Provider-backed market title."
          },
          "event_slug": {
            "type": ["string", "null"]
          },
          "event_id": {
            "type": ["string", "null"],
            "description": "Provider event id when available."
          },
          "parent_event_id": {
            "type": ["string", "null"],
            "description": "Provider parent-event id used as the first event-cap identity when available."
          },
          "game_start_time": {
            "type": "string",
            "format": "date-time",
            "description": "Provider-backed kickoff time in UTC."
          },
          "observed_at": {
            "type": "string",
            "format": "date-time",
            "description": "UTC instant when this row finished provider/holder evaluation."
          },
          "cohort": {
            "type": "string",
            "enum": ["wider_holder", "in_play", "emerging_pile"],
            "description": "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."
          },
          "admitted_by": {
            "type": "string",
            "enum": ["most_held", "soonest_kickoff", "most_held_48h", "most_held_48h_by_type"],
            "description": "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."
          },
          "observation_only": {
            "type": "boolean",
            "const": true,
            "description": "Always true. This row must not be routed to an order executor."
          },
          "piled_side": {
            "deprecated": true,
            "type": ["string", "null"],
            "description": "Nullable provider-backed piled-outcome display label. When provider group context is unavailable, it may remain a bare Yes/No/Over/Under; do not use it alone as participant identity. Deprecated (#16310): `side` is the canonical spelling and carries the same value; this key stays on the wire."
          },
          "piled_outcome_index": {
            "type": "integer",
            "enum": [0, 1],
            "description": "Provider binary-column selector: 0 selects outcome_yes/token_id_yes; 1 selects outcome_no/token_id_no. It does not identify home/away or a participant. Use piled_side together with title/event context for display."
          },
          "backed_price": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Aggregate piled-side market midpoint recorded at observed_at. This is an observation price mark, not a wallet entry cost."
          },
          "sharp_pct": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Piled-side graded-holder dollar concentration."
          },
          "backed_sharp_usd": {
            "type": "number",
            "minimum": 0,
            "description": "Raw graded-holder USD on the piled outcome."
          },
          "s_count": {
            "type": "integer",
            "minimum": 0
          },
          "a_count": {
            "type": "integer",
            "minimum": 0
          },
          "b_count": {
            "type": "integer",
            "minimum": 0
          },
          "graded_holders": {
            "type": "integer",
            "minimum": 1,
            "description": "Piled-side S/A/B holder count."
          },
          "top_grade": {
            "type": "string",
            "enum": ["S", "A", "B"]
          },
          "smart_score": {
            "deprecated": true,
            "type": "number",
            "minimum": -1,
            "maximum": 1,
            "description": "Canonical signed holder-pile score. Deprecated (#16310): `side_share` is the canonical spelling and carries the same value; this key stays on the wire."
          },
          "volume": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "Cumulative provider taker volume in shares, not cash or dollars."
          },
          "conviction_score": {
            "deprecated": true,
            "type": "number",
            "minimum": 0,
            "description": "Recorded conviction score; higher values indicate stronger conviction."
          },
          "provider_read_source": {
            "type": "string",
            "enum": ["cached", "live"],
            "description": "Whether the provider holder page came from the shared cache or a live provider read."
          },
          "holder_scan_complete": {
            "type": "boolean",
            "description": "True only when the provider page read for each outcome token listed every holder of that token. Observation collection reads one 100-row page per token; a token with more holders stays incomplete. False means holder counts and dollar totals measure the observed positive-holder subset. sharp_pct describes that observed subset and is not a lower bound on the full-population percentage. Incomplete scans cannot satisfy a future capital-promotion gate."
          },
          "holder_snapshot_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Proven provider holder observation time. A warm cache hit uses only the original provider completion time from its companion metadata, never cache-read time. A wider_holder or emerging_pile row whose holder read did not finish or failed in the current pass may reuse that market's last pregame holder page for up to 15 minutes; an in_play row may reuse its last in-play page, read after the provider reported the game live and never before that market's own kickoff, for up to 10 minutes. Both ages are counted when the snapshot is computed. Either reuse carries that page's original time here and provider_read_source cached. A pregame market more than an hour before kickoff reuses its last page the same way until that page is 10 minutes old, and only then is read again; while that market has had no trade since the page, it keeps reusing the page until it is 30 minutes old. Once that market's own kickoff has passed, an in_play row with provider_read_source cached, a warm hit or a reuse, never carries a page read before it. Null, malformed, future, or stale holder time fails in-play closed."
          },
          "directional_status": {
            "type": "string",
            "enum": ["available", "unknown_ungrouped", "unknown_stale", "unavailable"],
            "description": "Truthful state of the directional read, which classifies each graded holder by its fresh synced legs across the game's markets and, when holder_scan_complete is true, by Polymarket's currentValue on both outcomes of this market. A wider_holder row can remain emitted with unavailable and terminal wider_holder_emitted; in_play fails closed instead and terminates as in_play_directional_unavailable."
          },
          "one_way_holder_count": {
            "type": ["integer", "null"],
            "minimum": 0
          },
          "hedged_holder_count": {
            "type": ["integer", "null"],
            "minimum": 0
          },
          "one_way_graded_usd": {
            "type": ["number", "null"],
            "minimum": 0
          },
          "directional_confidence": {
            "type": ["number", "null"],
            "minimum": 0,
            "maximum": 1
          },
          "directional_rank_score": {
            "type": "number",
            "minimum": 0,
            "description": "Recorded side ordering score; higher values sort first."
          },
          "rank": {
            "type": "integer",
            "minimum": 1,
            "description": "1-based rank within this observation cohort and snapshot."
          },
          "market_context": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EdgeHunterMarketContext"
              },
              {
                "type": "null"
              }
            ],
            "description": "Required nullable frozen metadata context. Null only during the legacy-generation transition; selected reads require sidecar readiness and fail closed with 503 instead."
          }
        }
      },
      "EdgeHunterFunnelReport": {
        "type": "object",
        "description": "Per-sport accountable funnel for the full observation snapshot, returned on every page.",
        "required": ["sports"],
        "properties": {
          "sports": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EdgeHunterSportFunnelReport"
            }
          }
        }
      },
      "EdgeHunterSportFunnelReport": {
        "type": "object",
        "description": "Independent sports-board supply plus stored-universe terminal accounting for one canonical sport.",
        "required": [
          "sport",
          "board_input",
          "board_live_available",
          "board_upcoming_configured",
          "board_upcoming_available",
          "board_upcoming_status",
          "board_upcoming_unavailable_scopes",
          "input",
          "terminals",
          "terminal_total",
          "reconciled"
        ],
        "properties": {
          "sport": {
            "type": "string",
            "enum": [
              "Basketball",
              "Football",
              "Baseball",
              "Hockey",
              "MMA",
              "Boxing",
              "Soccer",
              "Cricket",
              "Golf",
              "Tennis",
              "Esports",
              "Racing",
              "Table Tennis",
              "Pickleball"
            ]
          },
          "board_input": {
            "type": "integer",
            "minimum": 0,
            "description": "Unique condition ids independently visible on the provider-first sports board."
          },
          "board_live_available": {
            "type": "boolean",
            "description": "Whether the always-applicable live-board source completed as available. False can mean a completed source failure (board_source_unavailable) or live-board work missing an internal configured-scope deadline or the outer fair-wave deadline (board_deadline_unavailable); inspect terminals to distinguish them."
          },
          "board_upcoming_configured": {
            "type": "boolean",
            "description": "Whether a provider-backed upcoming-board source is configured and applicable for this sport. False means not applicable, not provider failure."
          },
          "board_upcoming_available": {
            "type": "boolean",
            "description": "Whether every configured upcoming-board scope completed as available. False with board_upcoming_configured=false means not applicable. When board_upcoming_configured is true and this flag is false, read board_upcoming_status for the cause (unknown means no cause was recorded, which no computed snapshot reports): the board_source_unavailable and board_deadline_unavailable terminals are assigned only to already-started rows (the live half) and are structurally 0 for the upcoming source, so they never explain this flag."
          },
          "board_upcoming_status": {
            "type": "string",
            "enum": [
              "unknown",
              "not_configured",
              "available",
              "capacity_limited",
              "source_unavailable",
              "cold_unavailable",
              "deadline_unavailable"
            ],
            "description": "Why the upcoming-board source is (un)available. Board supply is one canonical-sport union: the bare category owns live truth and every configured composed league scope contributes upcoming rows; folded leagues without a configured board (currently CFL) are not in the upcoming union. available: every configured scope completed truthfully (a successful empty schedule still counts). capacity_limited: provider pagination or a configured upcoming cache published an intentionally bounded complete-event prefix; those rows are excluded from diagnostic-universe input and must not be treated as a complete upcoming universe. Cache-bound prefixes are limited to an exact 5,000,000-byte final envelope. source_unavailable: composition failed before a truthful union; resolved scope readers turn half failures into cold_unavailable, so fresh producers are whole-union identity reconciliation or a registry contract failure and carry zero rows. cold_unavailable: every scope completed but at least one reported its upcoming half unavailable because no servable entry was inside the stale-serve bound and the background warm did not land in time; it is not by itself proof of a provider outage. deadline_unavailable: an internal configured-scope deadline or the outer bounded fair wave expired. An internal deadline may retain healthy bare-category or sibling-scope rows; the outer wave records zero rows. These upcoming fields do not describe league live-membership availability. If the bare-category live scope fails, all live rows are dropped even when a league scope completed, because the bare category is the sole live-truth owner. not_configured: no upcoming scope applies to the sport. unknown: no cause was recorded; every computed snapshot reports a concrete status, so none reads unknown. board_upcoming_available is exactly board_upcoming_status == available."
          },
          "board_upcoming_unavailable_scopes": {
            "type": "array",
            "description": "Configured upcoming scopes that did not complete as available. Values are category, a provider league tag slug (nfl, cfb, nba, wnba, euroleague-basketball, ncaa-basketball, cwbb, nhl, mls, valorant, league-of-legends, counter-strike-2, or dota-2), registry when the compiled scope/projection contract drifted, union when cross-scope identity reconciliation failed, or wave when the outer fair-wave deadline expired before scope-level evidence returned. Empty means no unavailable upcoming scope was identified; this includes healthy/not-configured rows and a legacy cached row. Observation league scopes are upcoming-only and perform no live-membership read.",
            "items": {
              "type": "string",
              "enum": [
                "category",
                "nfl",
                "cfb",
                "nba",
                "wnba",
                "euroleague-basketball",
                "ncaa-basketball",
                "cwbb",
                "nhl",
                "mls",
                "valorant",
                "league-of-legends",
                "counter-strike-2",
                "dota-2",
                "registry",
                "union",
                "wave"
              ]
            },
            "uniqueItems": true
          },
          "input": {
            "type": "integer",
            "minimum": 0,
            "description": "Stored-universe rows plus provider-board rows missing from storage."
          },
          "terminals": {
            "type": "object",
            "description": "Sparse counts over the closed 25-value terminal vocabulary: outside_horizon, resolved, provider_closed, provider_excluded, invalid_market, missing_token, missing_stored_market, not_provider_live, board_source_unavailable, board_deadline_unavailable, primary_slate_candidate, zero_indexed_holder_research, capacity_limited, provider_unavailable, holder_deadline_unavailable, holder_computation_unavailable, holder_scan_incomplete, no_current_graded_holder, split_holder_pile, price_unavailable, wider_holder_emitted, in_play_emitted, in_play_stale_observed, in_play_directional_unavailable, or internal_unclassified. primary_slate_candidate means the view=signals snapshot named by signals_as_of lists the market at its widest selection (horizon_hours=48, min_grade=B, no selector), so it is not a wider_holder candidate; when no view=signals snapshot could be read (signals_as_of null), no market takes it. capacity_limited is intentional bounded provider-work admission, is fully accounted here, and does not itself set degraded=true. board_source_unavailable means a completed board source was unavailable; board_deadline_unavailable means live-board work missed either an internal configured-scope deadline or the outer fair-wave deadline; provider_unavailable means a holder read sent to the provider failed and the market had no reusable holder page; holder_deadline_unavailable means holder cache/provider work missed the absolute request deadline, or local capacity never sent the holder read, and the market had no reusable holder page; holder_computation_unavailable means post-holder provider or DB-backed price/metadata evaluation was unavailable.",
            "propertyNames": {
              "$ref": "#/components/schemas/EdgeHunterObservationTerminalReason"
            },
            "additionalProperties": {
              "type": "integer",
              "minimum": 0
            }
          },
          "terminal_total": {
            "type": "integer",
            "minimum": 0,
            "description": "Sum of every sparse terminal count."
          },
          "reconciled": {
            "type": "boolean",
            "description": "True exactly when input equals terminal_total."
          }
        }
      },
      "EdgeHunterObservationTerminalReason": {
        "type": "string",
        "description": "Closed 25-value terminal-reason vocabulary for the accountable Edge Hunter observation funnel. capacity_limited is intentional bounded provider-work admission and does not itself set the snapshot degraded. board_source_unavailable is a completed board-source failure; board_deadline_unavailable means live-board work missed either an internal configured-scope deadline or the outer fair-wave deadline; both classify only already-started rows, so for the upcoming source read funnel.sports[].board_upcoming_status instead; provider_unavailable is reserved for a holder read sent to the provider that failed, with no reusable holder page; holder_deadline_unavailable is holder cache/provider absolute-deadline exhaustion or a holder read local capacity never sent, with no reusable holder page.",
        "enum": [
          "outside_horizon",
          "resolved",
          "provider_closed",
          "provider_excluded",
          "invalid_market",
          "missing_token",
          "missing_stored_market",
          "not_provider_live",
          "board_source_unavailable",
          "board_deadline_unavailable",
          "primary_slate_candidate",
          "zero_indexed_holder_research",
          "capacity_limited",
          "provider_unavailable",
          "holder_deadline_unavailable",
          "holder_computation_unavailable",
          "holder_scan_incomplete",
          "no_current_graded_holder",
          "split_holder_pile",
          "price_unavailable",
          "wider_holder_emitted",
          "in_play_emitted",
          "in_play_stale_observed",
          "in_play_directional_unavailable",
          "internal_unclassified"
        ]
      },
      "EdgeHunterBoardResponse": {
        "type": "object",
        "required": ["object", "data", "meta"],
        "properties": {
          "object": {
            "type": "string",
            "const": "edge_hunter"
          },
          "data": {
            "$ref": "#/components/schemas/EdgeHunterBoard"
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          },
          "selection": {
            "$ref": "#/components/schemas/EdgeHunterSelection",
            "description": "Normalized axes requested with a selector or category; omitted on an unselected default read."
          }
        }
      },
      "EdgeHunterSignalsResponse": {
        "type": "object",
        "required": ["object", "view", "data", "has_more", "meta"],
        "properties": {
          "object": {
            "type": "string",
            "const": "list"
          },
          "view": {
            "type": "string",
            "const": "signals"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EdgeHunterRankedSignal"
            }
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": "string"
          },
          "total": {
            "type": "integer"
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          },
          "selection": {
            "$ref": "#/components/schemas/EdgeHunterSelection",
            "description": "Normalized axes requested with a selector or category; omitted on an unselected default read."
          }
        },
        "description": "Full Edge Hunter signals list envelope. The view literal distinguishes advanced collections, including empty pages."
      },
      "EdgeHunterObservationDegradationReason": {
        "type": "object",
        "description": "One observed cause of operational degradation in the canonical all-sports observation generation. Reasons are independent of the one-terminal-per-input funnel and remain unchanged through category, cohort and selector projection. Intentional capacity limits and an unconfigured upcoming source are not degradation reasons.",
        "required": ["reason", "sport"],
        "properties": {
          "reason": {
            "type": "string",
            "enum": [
              "holder_scan_incomplete",
              "live_source_stale",
              "directional_unavailable",
              "funnel_unreconciled",
              "board_live_unavailable",
              "board_upcoming_unavailable",
              "provider_unavailable",
              "holder_deadline_unavailable",
              "holder_computation_unavailable",
              "missing_stored_market",
              "price_unavailable",
              "in_play_stale_observed",
              "in_play_directional_unavailable",
              "internal_unclassified",
              "board_source_unavailable",
              "board_deadline_unavailable"
            ],
            "description": "Recorded producer cause. holder_scan_incomplete is retired and no longer emitted: the one-page holder read is an intentional bound, disclosed by each row's holder_scan_complete and by coverage.incomplete_holder_markets, and it does not degrade a generation. directional_unavailable can accompany an emitted wider_holder row; live_source_stale means provider live evidence exceeded its freshness bound. Other values identify reconciliation, applicable board-source or terminal failure evidence."
          },
          "sport": {
            "type": ["string", "null"],
            "description": "Canonical sport for the recorded cause; null only for generation-wide evidence without a sport attribution."
          }
        },
        "example": {
          "reason": "holder_deadline_unavailable",
          "sport": "Soccer"
        }
      },
      "EdgeHunterObservationCoverage": {
        "type": "object",
        "description": "Measured coverage of the frozen canonical observation generation and this requested page. For sports and esports reads, the first four counts remain global through category, cohort and all selectors; with admission=most_held_48h they count that selection's generation, where every wider_holder candidate it did not take is capacity_limited. They are neither a census of all provider markets nor a count of successfully evaluated holders. Selected and returned counts describe the requested projection. An unmappable legacy category synthesizes a zero-work empty generation with all six counts zero and no degradation reasons; it does not read the all-sports cache.",
        "required": [
          "input_markets",
          "capacity_limited_markets",
          "emitted_observations",
          "incomplete_holder_markets",
          "selected_observations",
          "returned_observations"
        ],
        "properties": {
          "input_markets": {
            "type": "integer",
            "minimum": 0,
            "description": "Sum of canonical source-generation funnel input across all sports, before category, cohort or selector projection."
          },
          "capacity_limited_markets": {
            "type": "integer",
            "minimum": 0,
            "description": "Canonical source-generation input assigned capacity_limited. These markets were intentionally outside the bounded holder-work admission and are not missing emitted rows. It includes the admitted pregame wider_holder markets of any sport no request named in the last 30 minutes, whose holders the generation did not read."
          },
          "emitted_observations": {
            "type": "integer",
            "minimum": 0,
            "description": "All wider_holder and in_play observations emitted in the canonical source generation, before cohort, category or selector projection. Emerging pile is an overlapping projection and does not add source emissions."
          },
          "incomplete_holder_markets": {
            "type": "integer",
            "minimum": 0,
            "description": "Canonical source-generation markets whose attempted holder scan did not establish complete coverage, including incomplete scans that did not emit an observation. Collection reads one 100-row page per token, so a market with more holders on a token counts here by design; this count does not by itself degrade the generation."
          },
          "selected_observations": {
            "type": "integer",
            "minimum": 0,
            "description": "Observations matching the requested cohort, category, selectors and applicable pinned projection cutoff before pagination."
          },
          "returned_observations": {
            "type": "integer",
            "minimum": 0,
            "description": "Observation rows on this page; equals data.length."
          }
        }
      },
      "EdgeHunterObservationsResponse": {
        "type": "object",
        "required": [
          "object",
          "view",
          "data",
          "has_more",
          "next_cursor",
          "snapshot_as_of",
          "degraded",
          "degradation_reasons",
          "coverage",
          "funnel",
          "meta"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "list"
          },
          "view": {
            "type": "string",
            "const": "observations"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EdgeHunterObservation"
            }
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": ["string", "null"],
            "description": "Pass as cursor for the next page. Always sent; null on the last page."
          },
          "snapshot_as_of": {
            "type": "string",
            "format": "date-time",
            "description": "Completion time of the shared observation snapshot pinned by the cursor."
          },
          "degraded": {
            "type": "boolean",
            "description": "True when an operational failure or unknown provider-board, holder, directional, reconciliation, or internal completeness state made this snapshot partial. This is snapshot-wide and can retain degradation that the funnel's one-terminal-per-input accounting cannot represent. Inspect degradation_reasons for every recorded source-generation cause and its nullable canonical sport attribution. Intentional bounds do not by themselves set this field: capacity_limited rows remain fully accounted in the funnel, and a holder scan the one-page read leaves incomplete counts in coverage.incomplete_holder_markets; board_upcoming_status=not_configured is not a failure."
          },
          "degradation_reasons": {
            "type": "array",
            "uniqueItems": true,
            "items": {
              "$ref": "#/components/schemas/EdgeHunterObservationDegradationReason"
            },
            "description": "Sorted, deduplicated causes from the canonical all-sports generation, unchanged by category, cohort or selectors; with admission=most_held_48h, from that selection's generation. Empty exactly when degraded is false. Capacity-limited input, the one-page holder bound (holder_scan_complete=false) and board_upcoming_status=not_configured do not by themselves add a reason."
          },
          "coverage": {
            "$ref": "#/components/schemas/EdgeHunterObservationCoverage"
          },
          "funnel": {
            "$ref": "#/components/schemas/EdgeHunterFunnelReport"
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          },
          "selection": {
            "$ref": "#/components/schemas/EdgeHunterSelection",
            "description": "Normalized axes requested with a selector or category; omitted on an unselected default read."
          },
          "admission": {
            "type": "string",
            "enum": ["most_held_48h", "most_held_48h_by_type"],
            "x-narrowed": true,
            "description": "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."
          },
          "departures": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EdgeHunterObservationDeparture"
            },
            "maxItems": 336,
            "description": "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."
          },
          "signals_as_of": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "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."
          }
        },
        "description": "Full Edge Hunter observations list envelope. Required degradation_reasons explains the source-generation verdict; required coverage distinguishes source input, intentional capacity exclusions, source emissions, incomplete holder scans, selection and the returned page. The view literal distinguishes advanced collections, including empty pages."
      },
      "EdgeHunterObservationDeparture": {
        "type": "object",
        "description": "A market whose wider_holder card left this selection before kickoff, with why it left.",
        "required": [
          "condition_id",
          "event_slug",
          "category",
          "admitted_by",
          "game_start_time",
          "last_observed_at",
          "departed_at",
          "reason"
        ],
        "properties": {
          "condition_id": {
            "type": "string",
            "description": "Raw Polymarket condition id."
          },
          "event_slug": {
            "type": ["string", "null"]
          },
          "category": {
            "type": "string",
            "enum": [
              "Basketball",
              "Football",
              "Baseball",
              "Hockey",
              "MMA",
              "Boxing",
              "Soccer",
              "Cricket",
              "Golf",
              "Tennis",
              "Esports",
              "Racing",
              "Table Tennis",
              "Pickleball"
            ],
            "description": "Canonical sport bucket the departed card carried."
          },
          "admitted_by": {
            "type": "string",
            "enum": ["most_held", "soonest_kickoff", "most_held_48h", "most_held_48h_by_type"],
            "description": "The departed card's admitted_by: most_held_48h on an admission=most_held_48h response."
          },
          "game_start_time": {
            "type": "string",
            "format": "date-time",
            "description": "Kickoff the departed card carried, in UTC. The entry leaves the list once it passes."
          },
          "last_observed_at": {
            "type": "string",
            "format": "date-time",
            "description": "The departed card's observed_at: when its last evaluation finished."
          },
          "departed_at": {
            "type": "string",
            "format": "date-time",
            "description": "snapshot_as_of of the first snapshot of this selection without the card."
          },
          "reason": {
            "$ref": "#/components/schemas/EdgeHunterObservationTerminalReason",
            "description": "Why the market has no card: its terminal in this selection's funnel in the snapshot it left, and while that terminal reports a read that did not finish (holder_deadline_unavailable, provider_unavailable, holder_computation_unavailable, internal_unclassified), the terminal of each later snapshot until one answers; an answered reason stays, except as view=signals starts or stops listing the market. primary_slate_candidate: view=signals lists the market. While the entry stays, a later snapshot that read view=signals and no longer excludes the market replaces it with that snapshot's terminal, one that excludes the market replaces any other reason with it, and one with signals_as_of null leaves it as it is. capacity_limited: it lost its evaluation place without another outcome. missing_stored_market: the market was no longer in the stored market universe. Any other value means what it means in the funnel, for example split_holder_pile, no_current_graded_holder or resolved."
          }
        }
      },
      "EdgeHunterSelection": {
        "type": "object",
        "description": "Normalized requested selection axes. Only requested axes appear; omitted for unselected defaults. Arrays are nonempty, sorted and deduplicated. OR within an axis, AND across axes.",
        "properties": {
          "kind": {
            "type": "string",
            "enum": ["sports", "esports"]
          },
          "category": {
            "type": "string",
            "description": "Resolved legacy canonical bucket or non_sport for an unmappable category."
          },
          "sports": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "type": "string"
            },
            "description": "Canonical sport buckets, including Esports and Table Tennis, matched case-insensitively. Unknown names and league aliases such as NFL are rejected in sports; use category for legacy bucket aliases or leagues for exact league selection. Omission covers every sport admitted by the selected view."
          },
          "leagues": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "type": "string"
            },
            "description": "Normalized machine/provider league identities, such as nfl, cfb, nba, epl, cs2, lol, dota2 or valorant. Known wire/tag aliases normalize; other provider keys match exact lowercase identity. This is separate from category: category=NFL selects Football, while leagues=nfl selects NFL only. Read market_context.league for authoritative values."
          },
          "market_types": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "type": "string"
            },
            "description": "Exact provider sports_market_type values. This is an open provider taxonomy, distinct from exact market IDs. Read market_context.market_type; missing selected metadata excludes the row."
          },
          "condition_ids": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "type": "string"
            },
            "description": "Exact market selections. Raw provider condition IDs and the existing mkt_-prefixed aliases normalize to raw IDs. Unknown well-formed IDs return an empty result."
          },
          "event_slugs": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "type": "string"
            },
            "description": "Exact provider event slugs. Use event_slug returned on the row; no title or slug-prefix guessing."
          },
          "series_slugs": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "type": "string"
            },
            "description": "Exact provider series slugs. Read market_context.series_slug; a missing selected series excludes the row."
          }
        }
      },
      "EdgeHunterMarketContext": {
        "type": "object",
        "description": "Metadata frozen with the read generation. Values are nullable when the provider/canonical source has no value; no title-based inference or current-clock fallback.",
        "required": ["league", "series_slug", "market_type", "metadata_updated_at"],
        "properties": {
          "league": {
            "type": ["string", "null"],
            "description": "Normalized machine/provider league identity. Known wire/tag aliases normalize; other provider identities match exact lowercase keys."
          },
          "series_slug": {
            "type": ["string", "null"],
            "description": "Exact provider series slug, usable in series_slugs selection."
          },
          "market_type": {
            "type": ["string", "null"],
            "description": "Exact provider sports_market_type, usable in market_types selection."
          },
          "metadata_updated_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Exact local canonical metadata writer market_canonical.updated_at. This is not a provider observation clock; null means unavailable."
          }
        }
      }
    },
    "responses": {
      "WebhookObject": {
        "description": "Webhook destination",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": ["object", "data", "meta"],
              "properties": {
                "object": {
                  "type": "string",
                  "const": "webhook"
                },
                "data": {
                  "$ref": "#/components/schemas/WebhookEndpoint"
                },
                "meta": {
                  "$ref": "#/components/schemas/ResponseMeta"
                }
              }
            }
          }
        }
      },
      "WebhookList": {
        "description": "Webhook destination list",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": ["object", "data", "has_more", "meta"],
              "properties": {
                "object": {
                  "type": "string",
                  "const": "list"
                },
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookEndpoint"
                  }
                },
                "has_more": {
                  "type": "boolean"
                },
                "next_cursor": {
                  "type": "string"
                },
                "total": {
                  "type": "integer"
                },
                "meta": {
                  "$ref": "#/components/schemas/ResponseMeta"
                }
              }
            }
          }
        }
      },
      "BadRequest": {
        "description": "Invalid request parameter",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "SubscriptionRequired": {
        "description": "Active Pro subscription required. The key is valid but the account has no paid access: error.reason is subscription_inactive when the Pro subscription has lapsed, or payment_overdue when the plan stands but its latest invoice is unpaid (#32592). error.billing_url and error.message name where a person clears it (https://0xinsider.com/billing). Permanent until a person acts: no Retry-After, never retry on a schedule.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Account access denied",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "Locked": {
        "description": "Account is locked",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "RequestTimeout": {
        "description": "Request exceeded the server's 30-second transport timeout. The timeout response has an empty body because it is generated before handler-level JSON error shaping.",
        "x-empty-body": true
      },
      "RateLimited": {
        "description": "Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user on Pro, 200 on Max (sliding window), on every authenticated route; RateLimit-Limit reports the caller's. On the remote MCP endpoint /api/v1/mcp only tools/call is counted: initialize, ping, tools/list, notifications, and the GET, HEAD and DELETE the endpoint answers 405 spend no per-minute request, no monthly quota and no pay-as-you-go usage, with or without a key. (2) On the BATCH routes only: 2500 batch item units/minute per user on Pro, 5000 on Max, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch on Pro, 5000 = 200 x 25 on Max, which is the most item work a key can buy through the request limiter at all: a caller may spend their plan's entire request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 500,000 and Max includes 2,000,000 authenticated requests per UTC calendar month. Over the plan's included requests: with pay as you go on, the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to four times the included allowance (2,000,000 requests for Pro); without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset. Pay-as-you-go accounts receive the same refusal at their ceiling. A refused request is not counted. X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month) are on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call. (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.",
        "headers": {
          "Retry-After": {
            "description": "Seconds until rate limit resets.",
            "schema": {
              "type": "integer"
            }
          },
          "RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimit-Limit"
          },
          "RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimit-Remaining"
          },
          "RateLimit-Reset": {
            "$ref": "#/components/headers/RateLimit-Reset"
          },
          "X-RateLimit-Limit": {
            "schema": {
              "type": "integer"
            }
          },
          "X-RateLimit-Remaining": {
            "schema": {
              "type": "integer"
            }
          },
          "X-RateLimit-Reset": {
            "schema": {
              "type": "integer"
            }
          },
          "X-Request-Id": {
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "RateLimitUnavailable": {
        "description": "Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown",
        "headers": {
          "Retry-After": {
            "description": "Seconds until the middleware will probe the Redis-backed rate limiter again.",
            "schema": {
              "type": "integer"
            }
          },
          "X-Request-Id": {
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "InternalError": {
        "description": "Unexpected server error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "IdempotencyInProgress": {
        "description": "An Idempotency-Key request with the same body is still in progress. Retry shortly with the same key and body.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            },
            "examples": {
              "in_progress": {
                "summary": "Idempotency request still in progress",
                "value": {
                  "object": "error",
                  "error": {
                    "code": "bad_request",
                    "message": "Your previous request is still processing. Retry in a moment.",
                    "param": "Idempotency-Key",
                    "reason": "idempotency_in_progress"
                  },
                  "meta": {
                    "request_id": "req_example",
                    "cached": false,
                    "cost": 1
                  }
                }
              }
            }
          }
        }
      },
      "IdempotencyConflict": {
        "description": "The Idempotency-Key was already used with a different request body.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            },
            "examples": {
              "different_body": {
                "summary": "Idempotency key reused with a different body",
                "value": {
                  "object": "error",
                  "error": {
                    "code": "bad_request",
                    "message": "Idempotency-Key already used with a different request body",
                    "param": "Idempotency-Key"
                  },
                  "meta": {
                    "request_id": "req_example",
                    "cached": false,
                    "cost": 1
                  }
                }
              }
            }
          }
        }
      },
      "PickNotReleased": {
        "description": "No pick is published for the current product day. Scheduled selections retain their returned release time. The product day uses America/New_York, and a day can have no published picks.\n\nThe body carries `error.code=\"not_found\"`, `error.reason=\"pick_not_released\"`, and `error.retry_at`. The response sets `Retry-After`. Both retry fields name the same recommended future instant.\n\nThe recommendation is advisory and can change. Schedule the next request from the returned retry guidance instead of calculating a release schedule or polling.",
        "headers": {
          "Retry-After": {
            "description": "Seconds until the recommended next request. Always at least 1. Names the same instant as `error.retry_at`. Prefer this header for the sleep duration; it is immune to clock skew.",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "ReadModelWarming": {
        "description": "Service unavailable. On this route a 503 has TWO distinct causes; branch on error.reason. (1) error.reason=\"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; consult that endpoint's contract and do not infer dependency health from this shared reason. This is endpoint-local unavailability, not rate limiting: retry only this route after Retry-After (or error.retry_at), and do not feed it into a rate-limit backoff shared with other endpoints. (2) no error.reason: the Redis-backed authenticated rate limiter is unavailable and the middleware failed closed; Retry-After is the seconds until it probes Redis again. Both carry error.code=\"rate_limit_unavailable\" (a FROZEN contract value, so it cannot be split per cause) and X-Request-Id -- which is why error.reason, not error.code, is the discriminator.",
        "headers": {
          "Retry-After": {
            "description": "Seconds until retrying is worth doing. With error.reason=\"read_model_warming\" this is the endpoint-local read-model retry interval; without a reason it is the rate-limiter outage cooldown. Always >= 1.",
            "schema": {
              "type": "integer"
            }
          },
          "X-Request-Id": {
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "CursorExpired": {
        "description": "Bad request. On this cursor-paginated route a 400 has TWO distinct causes; branch on error.reason. (1) error.reason=\"cursor_expired\" (with error.param=\"cursor\"): the pagination cursor was invalidated by an upstream data change mid-walk (e.g. the ranking snapshot behind the page refreshed). It is NOT a malformed parameter and NOT a reason to stop: recovery is mechanical -- re-request the first page and walk forward again. There is deliberately no Retry-After and no error.retry_at, because waiting changes nothing. (2) no error.reason: an ordinary invalid request parameter -- check error.param when present, otherwise error.message. Both carry error.code=\"bad_request\" (a FROZEN contract value), so error.reason is the discriminator.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "TraderNotTracked": {
        "description": "Not found. On this route a 404 has FOUR distinct causes; branch on error.reason. (1) error.reason=\"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), so we capture no timeline for them. This is TERMINAL -- there is no Retry-After and no error.retry_at, because neither retrying nor re-spelling the path will ever succeed. Stop requesting this wallet. (2) no error.reason: the trader id or address does not resolve at all. Both carry error.code=\"not_found\" (a FROZEN contract value), so error.reason is the discriminator -- and since this endpoint has singular and plural path spellings, \"I used the wrong URL\" is a plausible enough wrong guess that the distinction is worth branching on. (3) error.reason=\"market_out_of_scope\" (#27311): condition_id names a market outside sports and esports, which 0xinsider serves exclusively. This is terminal too: stop requesting this market. (4) error.reason=\"fill_history_too_large\" (#33245): the wallet and market are tracked, but the wallet has more than 20,000 stored fills on the market before the requested page, and the timeline sums every earlier fill into its running totals. Terminal: stop requesting this pair.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      }
    },
    "headers": {
      "Sunset": {
        "description": "RFC 8594 HTTP-date when this deprecated alias stops serving: 2027-02-01T00:00:00Z (#29351). From that instant the path answers 410 Gone with error.code endpoint_retired; call the successor its Link header names (rel=\"successor-version\").",
        "schema": {
          "type": "string",
          "example": "Mon, 01 Feb 2027 00:00:00 GMT"
        }
      },
      "X-RateLimit-Limit": {
        "description": "Request limit of the budget this request was counted against, for its current window: the API key's per-minute sliding window on an authenticated call, at its plan's limit (100 requests on Pro, 200 on Max); the control-plane bucket GET /api/v1/me and GET /api/v1/usage share, the same on every plan, on a 429 from either; and the per-IP budget on a public route, on a refused credential (401, 402, 403, 423), and on a remote MCP message other than tools/call.",
        "schema": {
          "type": "integer",
          "example": 100
        }
      },
      "RateLimit-Limit": {
        "description": "Request limit of the budget this request was counted against, for its current window: the API key's per-minute sliding window on an authenticated call, at its plan's limit (100 requests on Pro, 200 on Max); the control-plane bucket GET /api/v1/me and GET /api/v1/usage share, the same on every plan, on a 429 from either; and the per-IP budget on a public route, on a refused credential (401, 402, 403, 423), and on a remote MCP message other than tools/call, none of which reaches the per-key limiter. Standard RateLimit header spelling.",
        "schema": {
          "type": "integer",
          "example": 100
        }
      },
      "X-RateLimit-Remaining": {
        "description": "Requests remaining in that budget's current window after this response.",
        "schema": {
          "type": "integer",
          "example": 84
        }
      },
      "X-RateLimit-Reset": {
        "description": "Unix timestamp when that budget's current window resets.",
        "schema": {
          "type": "integer",
          "example": 1710772860
        }
      },
      "RateLimit-Remaining": {
        "description": "Requests remaining in that budget's current window after this response. Standard RateLimit header spelling.",
        "schema": {
          "type": "integer",
          "example": 84
        }
      },
      "RateLimit-Reset": {
        "description": "Seconds until that budget's current window resets. Standard RateLimit header spelling.",
        "schema": {
          "type": "integer",
          "example": 42
        }
      },
      "X-Request-Id": {
        "description": "Server-generated request identifier for support and tracing. On every /api/v1 response, including 304, 408, CORS preflights and every error, and always equal to meta.request_id in the body. It is the key of the request's usage accounting row and of every log line the request emitted, so quote either form to support. A client-supplied X-Request-Id request header is ignored: the value is never adopted or echoed.",
        "schema": {
          "type": "string",
          "example": "req_550e8400"
        }
      },
      "X-Monthly-Quota-Limit": {
        "description": "Authenticated requests the account's plan includes per UTC calendar month (#16111): 500,000 for Pro, 2,000,000 for Max. Present on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call.",
        "schema": {
          "type": "integer",
          "example": 500000
        }
      },
      "X-Monthly-Quota-Remaining": {
        "description": "Included requests left this UTC calendar month; 0 once the quota is used. Present on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call.",
        "schema": {
          "type": "integer",
          "example": 458770
        }
      },
      "X-Monthly-Quota-Reset": {
        "description": "Unix seconds: the first instant of the next UTC calendar month, when the quota resets. Present on every response a route answers for a counted request, on the monthly-quota 429, and on GET /api/v1/me and GET /api/v1/usage, which read the month without spending it. Any other refusal or failure before the route runs, such as a per-minute 429 or a 401, carries none, nor does a remote MCP message other than tools/call.",
        "schema": {
          "type": "integer",
          "example": 1793491200
        }
      },
      "ETag": {
        "description": "Weak semantic validator for conditional GET. Request-specific response metadata is excluded; send as If-None-Match to receive 304 when the stable payload is unchanged.",
        "schema": {
          "type": "string",
          "example": "W/\"8f14e45fceea167a5a36dedd4bea2543\""
        }
      },
      "X-Usage-Accounting": {
        "description": "Usage-record persistence for a protected V1 handler response. persisted: confirmed row; failed: write failed; unknown: completion could not be confirmed. Independent of handler success; do not replay successful mutations to repair accounting. Absent before accounting admission and on public routes. The zero-cost /api/v1/usage route also omits it.",
        "schema": {
          "type": "string",
          "enum": ["persisted", "failed", "unknown"]
        }
      },
      "Server-Timing": {
        "description": "Processing time in milliseconds, for example api;dur=12.345. Includes API authentication, quota admission, handler work and response construction. Excludes network transit and streamed body or export-file transfer. The engineering budget is strictly below 250 ms; this header reports observations, not a latency guarantee or a new timeout.",
        "schema": {
          "type": "string"
        },
        "example": "api;dur=12.345"
      },
      "X-Query-Ignored": {
        "description": "Comma-separated, percent-encoded query names the operation did not publish and therefore ignored in compatible mode. Names are sorted and de-duplicated.",
        "schema": {
          "type": "string"
        }
      },
      "X-Effective-Query": {
        "description": "Normalized, percent-encoded query string containing only the recognized names and values applied by the operation. Query names and values use form-urlencoded decoding, where + is a space. Repeated names are retained and sorted by name. A limit outside the operation's published minimum..maximum is reported as the clamped value the page used, so the header states the page size served rather than the one requested.",
        "schema": {
          "type": "string"
        }
      },
      "X-Query-Unmatched": {
        "description": "Comma-separated, percent-encoded names of recognized query parameters whose value the operation applied but which matched nothing it serves, so the empty page reflects that filter, not a quiet catalog. Sent only by an operation that keeps such a parameter lenient on purpose: on GET /api/v1/games it names sport when the bucket is outside the sports this deployment serves (coverage.sports lists them). A value the operation refuses answers 400 instead, and an unknown parameter name is reported in X-Query-Ignored.",
        "schema": {
          "type": "string"
        }
      }
    }
  },
  "tags": [
    {
      "name": "Traders",
      "description": "Traders, batch lookups, timelines, and export readiness."
    },
    {
      "name": "Positions",
      "description": "Current prediction-market position snapshots from backend-owned mirrors."
    },
    {
      "name": "Large Positions",
      "description": "Largest current open positions from graded traders (Polymarket-only)."
    },
    {
      "name": "Large trades",
      "description": "Recent and historical large trades."
    },
    {
      "name": "Leaderboard",
      "description": "Ranked trader discovery and category/strategy leaderboards."
    },
    {
      "name": "Pick of the Day",
      "description": "One sourced sharp-money call a day: the side profitable wallets are backing, with pre-game odds, the holders, and the track record."
    },
    {
      "name": "Games",
      "description": "Sports and esports games: both sides, schedules, provider status and the Polymarket markets linked to each game."
    },
    {
      "name": "Markets",
      "description": "Market search, discovery, snapshots, and sharp-money flow."
    },
    {
      "name": "Content",
      "description": "Search across 0xinsider editorial content."
    },
    {
      "name": "Suspicious trades",
      "description": "Trades whose recorded suspicion score meets the live flag threshold."
    },
    {
      "name": "Insider Radar",
      "description": "Deprecated spelling of Suspicious trades; both operations stay live as aliases until their 2027-02-01 sunset (#29351)."
    },
    {
      "name": "Events",
      "description": "Durable public event replay streams."
    },
    {
      "name": "Streaming",
      "description": "Resumable real-time Server-Sent Events stream of live feed envelopes."
    },
    {
      "name": "Webhooks",
      "description": "Signed builder webhook destinations and delivery controls."
    },
    {
      "name": "Usage",
      "description": "Developer API budget and usage introspection."
    },
    {
      "name": "Onboarding",
      "description": "Self-serve agent registration: a sandbox key with no account, and the path to live access."
    },
    {
      "name": "System",
      "description": "Health and operational status checks."
    },
    {
      "name": "MCP",
      "description": "Remote Model Context Protocol transport."
    },
    {
      "name": "Reports",
      "description": "Daily, weekly, monthly, and trader export report snapshots."
    },
    {
      "name": "Account",
      "description": "Identify the account and credential authenticated for a paid API request."
    },
    {
      "name": "Combos",
      "description": "Polymarket multi-leg combo fills, details, and live counts."
    }
  ]
}
