Skip to main content

oxinsider/
models.rs

1// Code generated by cargo codegen from the 0xinsider OpenAPI document. DO NOT EDIT.
2
3//! Typed models for every schema the OpenAPI document names, and for the request
4//! and response bodies it defines inline.
5//!
6//! A field the document marks optional or nullable is an `Option`: `None` means the
7//! API did not report that value, which is not a zero. Unknown JSON keys are ignored
8//! and an unknown enum value lands in `Other`, so an additive API change never fails
9//! a response. Money and price fields are `f64`, the precision the API sends.
10
11// Descriptions are the document's own, quoted verbatim; a field it leaves
12// undescribed has no doc comment rather than an invented one.
13#![allow(missing_docs)]
14#![allow(rustdoc::bare_urls, rustdoc::broken_intra_doc_links, rustdoc::invalid_html_tags)]
15#![allow(clippy::doc_lazy_continuation, clippy::large_enum_variant)]
16
17use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
18
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
20#[non_exhaustive]
21pub struct AccountIdentity {
22    pub object: String,
23    pub data: AccountIdentityData,
24    pub meta: ResponseMeta,
25}
26
27#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
28#[non_exhaustive]
29pub struct AccountIdentityData {
30    pub user_id: i64,
31    pub credential_id: i64,
32    /// 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.
33    pub credential_kind: CredentialKind,
34    /// The credential is currently valid; revoked, expired or unknown credentials are rejected.
35    pub credential_status: String,
36    pub entitlement: AccountIdentityDataEntitlement,
37    /// The scopes an OAuth grant or integration key carries; null for full developer-key access.
38    #[serde(default)]
39    pub scopes: Option<Vec<String>>,
40}
41
42#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
43#[non_exhaustive]
44pub struct AccountIdentityDataEntitlement {
45    pub paid_data_access: PaidDataAccess,
46    /// When paid data access is lapsed, the caller should renew the subscription; otherwise null.
47    #[serde(default)]
48    pub recovery_action: Option<String>,
49}
50
51/// A value this release does not know is kept in `Other`, so a new value never fails a response.
52#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
53#[non_exhaustive]
54pub enum Action {
55    /// `buy`
56    #[serde(rename = "buy")]
57    Buy,
58    /// `sell`
59    #[serde(rename = "sell")]
60    Sell,
61    /// A value this release does not know, kept as sent.
62    #[serde(untagged)]
63    Other(String),
64}
65
66impl Action {
67    /// The value as the API spells it.
68    pub fn as_str(&self) -> &str {
69        match self {
70            Self::Buy => "buy",
71            Self::Sell => "sell",
72            Self::Other(value) => value,
73        }
74    }
75}
76
77impl From<&str> for Action {
78    fn from(value: &str) -> Self {
79        match value {
80            "buy" => Self::Buy,
81            "sell" => Self::Sell,
82            other => Self::Other(other.to_owned()),
83        }
84    }
85}
86
87impl std::fmt::Display for Action {
88    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89        f.write_str(self.as_str())
90    }
91}
92
93impl AsRef<str> for Action {
94    fn as_ref(&self) -> &str {
95        self.as_str()
96    }
97}
98
99#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
100#[non_exhaustive]
101pub struct ActivateWebhookSecretResponse {
102    pub object: String,
103    pub data: WebhookEndpoint,
104    pub meta: ResponseMeta,
105}
106
107/// A value this release does not know is kept in `Other`, so a new value never fails a response.
108#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
109#[non_exhaustive]
110pub enum ActiveWithin {
111    /// `all`
112    #[serde(rename = "all")]
113    All,
114    /// `7d`
115    #[serde(rename = "7d")]
116    V7d,
117    /// `30d`
118    #[serde(rename = "30d")]
119    V30d,
120    /// `90d`
121    #[serde(rename = "90d")]
122    V90d,
123    /// A value this release does not know, kept as sent.
124    #[serde(untagged)]
125    Other(String),
126}
127
128impl ActiveWithin {
129    /// The value as the API spells it.
130    pub fn as_str(&self) -> &str {
131        match self {
132            Self::All => "all",
133            Self::V7d => "7d",
134            Self::V30d => "30d",
135            Self::V90d => "90d",
136            Self::Other(value) => value,
137        }
138    }
139}
140
141impl From<&str> for ActiveWithin {
142    fn from(value: &str) -> Self {
143        match value {
144            "all" => Self::All,
145            "7d" => Self::V7d,
146            "30d" => Self::V30d,
147            "90d" => Self::V90d,
148            other => Self::Other(other.to_owned()),
149        }
150    }
151}
152
153impl std::fmt::Display for ActiveWithin {
154    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155        f.write_str(self.as_str())
156    }
157}
158
159impl AsRef<str> for ActiveWithin {
160    fn as_ref(&self) -> &str {
161        self.as_str()
162    }
163}
164
165/// A value this release does not know is kept in `Other`, so a new value never fails a response.
166#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
167#[non_exhaustive]
168pub enum Activity {
169    /// `all`
170    #[serde(rename = "all")]
171    All,
172    /// `active`
173    #[serde(rename = "active")]
174    Active,
175    /// `inactive`
176    #[serde(rename = "inactive")]
177    Inactive,
178    /// A value this release does not know, kept as sent.
179    #[serde(untagged)]
180    Other(String),
181}
182
183impl Activity {
184    /// The value as the API spells it.
185    pub fn as_str(&self) -> &str {
186        match self {
187            Self::All => "all",
188            Self::Active => "active",
189            Self::Inactive => "inactive",
190            Self::Other(value) => value,
191        }
192    }
193}
194
195impl From<&str> for Activity {
196    fn from(value: &str) -> Self {
197        match value {
198            "all" => Self::All,
199            "active" => Self::Active,
200            "inactive" => Self::Inactive,
201            other => Self::Other(other.to_owned()),
202        }
203    }
204}
205
206impl std::fmt::Display for Activity {
207    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208        f.write_str(self.as_str())
209    }
210}
211
212impl AsRef<str> for Activity {
213    fn as_ref(&self) -> &str {
214        self.as_str()
215    }
216}
217
218/// A value this release does not know is kept in `Other`, so a new value never fails a response.
219#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
220#[non_exhaustive]
221pub enum Admission {
222    /// `most_held_48h`
223    #[serde(rename = "most_held_48h")]
224    MostHeld48h,
225    /// `most_held_48h_by_type`
226    #[serde(rename = "most_held_48h_by_type")]
227    MostHeld48hByType,
228    /// A value this release does not know, kept as sent.
229    #[serde(untagged)]
230    Other(String),
231}
232
233impl Admission {
234    /// The value as the API spells it.
235    pub fn as_str(&self) -> &str {
236        match self {
237            Self::MostHeld48h => "most_held_48h",
238            Self::MostHeld48hByType => "most_held_48h_by_type",
239            Self::Other(value) => value,
240        }
241    }
242}
243
244impl From<&str> for Admission {
245    fn from(value: &str) -> Self {
246        match value {
247            "most_held_48h" => Self::MostHeld48h,
248            "most_held_48h_by_type" => Self::MostHeld48hByType,
249            other => Self::Other(other.to_owned()),
250        }
251    }
252}
253
254impl std::fmt::Display for Admission {
255    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
256        f.write_str(self.as_str())
257    }
258}
259
260impl AsRef<str> for Admission {
261    fn as_ref(&self) -> &str {
262        self.as_str()
263    }
264}
265
266/// A value this release does not know is kept in `Other`, so a new value never fails a response.
267#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
268#[non_exhaustive]
269pub enum AdmittedBy {
270    /// `most_held`
271    #[serde(rename = "most_held")]
272    MostHeld,
273    /// `soonest_kickoff`
274    #[serde(rename = "soonest_kickoff")]
275    SoonestKickoff,
276    /// `most_held_48h`
277    #[serde(rename = "most_held_48h")]
278    MostHeld48h,
279    /// `most_held_48h_by_type`
280    #[serde(rename = "most_held_48h_by_type")]
281    MostHeld48hByType,
282    /// A value this release does not know, kept as sent.
283    #[serde(untagged)]
284    Other(String),
285}
286
287impl AdmittedBy {
288    /// The value as the API spells it.
289    pub fn as_str(&self) -> &str {
290        match self {
291            Self::MostHeld => "most_held",
292            Self::SoonestKickoff => "soonest_kickoff",
293            Self::MostHeld48h => "most_held_48h",
294            Self::MostHeld48hByType => "most_held_48h_by_type",
295            Self::Other(value) => value,
296        }
297    }
298}
299
300impl From<&str> for AdmittedBy {
301    fn from(value: &str) -> Self {
302        match value {
303            "most_held" => Self::MostHeld,
304            "soonest_kickoff" => Self::SoonestKickoff,
305            "most_held_48h" => Self::MostHeld48h,
306            "most_held_48h_by_type" => Self::MostHeld48hByType,
307            other => Self::Other(other.to_owned()),
308        }
309    }
310}
311
312impl std::fmt::Display for AdmittedBy {
313    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
314        f.write_str(self.as_str())
315    }
316}
317
318impl AsRef<str> for AdmittedBy {
319    fn as_ref(&self) -> &str {
320        self.as_str()
321    }
322}
323
324/// 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.
325#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
326#[non_exhaustive]
327pub struct AgentRegistration {
328    /// 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.
329    pub api_key: String,
330    /// Always false: this key never reaches live data.
331    pub livemode: bool,
332    pub environment: String,
333    pub created_at: String,
334    pub sandbox: AgentRegistrationSandbox,
335    /// What live data needs, and where each credential comes from. Both need a person: an account with an active Pro subscription.
336    pub live_access: AgentRegistrationLiveAccess,
337}
338
339/// What live data needs, and where each credential comes from. Both need a person: an account with an active Pro subscription.
340#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
341#[non_exhaustive]
342pub struct AgentRegistrationLiveAccess {
343    /// The production V1 base URL.
344    pub api_base_url: String,
345    /// What a live credential needs, in one sentence.
346    pub requirement: String,
347    /// Where a signed-in Pro user creates a live key (oxi_sk_live_).
348    pub api_keys_url: String,
349    /// RFC 8414 authorization server metadata, for an OAuth 2.1 grant the user approves.
350    pub oauth_authorization_server_metadata_url: String,
351    /// RFC 7591 dynamic client registration for public OAuth clients.
352    pub oauth_registration_endpoint: String,
353    /// The Pro plan.
354    pub pricing_url: String,
355    /// The authentication walkthrough for agents.
356    pub auth_guide_url: String,
357}
358
359#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
360#[non_exhaustive]
361pub struct AgentRegistrationSandbox {
362    /// 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.
363    pub api_base_url: String,
364    /// A read to send with the key.
365    pub first_request_url: String,
366    /// The OpenAPI document, served by the sandbox.
367    pub openapi_url: String,
368}
369
370/// A value this release does not know is kept in `Other`, so a new value never fails a response.
371#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
372#[non_exhaustive]
373pub enum Allocation {
374    /// `exact`
375    #[serde(rename = "exact")]
376    Exact,
377    /// `degraded`
378    #[serde(rename = "degraded")]
379    Degraded,
380    /// A value this release does not know, kept as sent.
381    #[serde(untagged)]
382    Other(String),
383}
384
385impl Allocation {
386    /// The value as the API spells it.
387    pub fn as_str(&self) -> &str {
388        match self {
389            Self::Exact => "exact",
390            Self::Degraded => "degraded",
391            Self::Other(value) => value,
392        }
393    }
394}
395
396impl From<&str> for Allocation {
397    fn from(value: &str) -> Self {
398        match value {
399            "exact" => Self::Exact,
400            "degraded" => Self::Degraded,
401            other => Self::Other(other.to_owned()),
402        }
403    }
404}
405
406impl std::fmt::Display for Allocation {
407    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
408        f.write_str(self.as_str())
409    }
410}
411
412impl AsRef<str> for Allocation {
413    fn as_ref(&self) -> &str {
414        self.as_str()
415    }
416}
417
418/// A computed count with its truth state; the same envelope as AnalyticNumber.
419#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
420#[non_exhaustive]
421pub struct AnalyticInteger {
422    pub state: AnalyticNumberState,
423    pub source: TrustSourceKind,
424    #[serde(default, skip_serializing_if = "Option::is_none")]
425    pub value: Option<i64>,
426    #[serde(default, skip_serializing_if = "Option::is_none")]
427    pub freshness_at: Option<String>,
428}
429
430/// 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.
431#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
432#[non_exhaustive]
433pub struct AnalyticNumber {
434    /// 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.
435    pub state: AnalyticNumberState,
436    /// Where the value came from, for diagnostics: cache is a stored aggregate, computed a request-time aggregate. Decide on state, not source.
437    pub source: TrustSourceKind,
438    #[serde(default, skip_serializing_if = "Option::is_none")]
439    pub value: Option<f64>,
440    /// When the stored inputs behind the value were written or last confirmed (cache), or the request time (computed).
441    #[serde(default, skip_serializing_if = "Option::is_none")]
442    pub freshness_at: Option<String>,
443}
444
445/// A value this release does not know is kept in `Other`, so a new value never fails a response.
446#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
447#[non_exhaustive]
448pub enum AnalyticNumberState {
449    /// `computed`
450    #[serde(rename = "computed")]
451    Computed,
452    /// `known_zero`
453    #[serde(rename = "known_zero")]
454    KnownZero,
455    /// `not_computed`
456    #[serde(rename = "not_computed")]
457    NotComputed,
458    /// `not_applicable`
459    #[serde(rename = "not_applicable")]
460    NotApplicable,
461    /// `stale`
462    #[serde(rename = "stale")]
463    Stale,
464    /// `unavailable`
465    #[serde(rename = "unavailable")]
466    Unavailable,
467    /// `insufficient_data`
468    #[serde(rename = "insufficient_data")]
469    InsufficientData,
470    /// A value this release does not know, kept as sent.
471    #[serde(untagged)]
472    Other(String),
473}
474
475impl AnalyticNumberState {
476    /// The value as the API spells it.
477    pub fn as_str(&self) -> &str {
478        match self {
479            Self::Computed => "computed",
480            Self::KnownZero => "known_zero",
481            Self::NotComputed => "not_computed",
482            Self::NotApplicable => "not_applicable",
483            Self::Stale => "stale",
484            Self::Unavailable => "unavailable",
485            Self::InsufficientData => "insufficient_data",
486            Self::Other(value) => value,
487        }
488    }
489}
490
491impl From<&str> for AnalyticNumberState {
492    fn from(value: &str) -> Self {
493        match value {
494            "computed" => Self::Computed,
495            "known_zero" => Self::KnownZero,
496            "not_computed" => Self::NotComputed,
497            "not_applicable" => Self::NotApplicable,
498            "stale" => Self::Stale,
499            "unavailable" => Self::Unavailable,
500            "insufficient_data" => Self::InsufficientData,
501            other => Self::Other(other.to_owned()),
502        }
503    }
504}
505
506impl std::fmt::Display for AnalyticNumberState {
507    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
508        f.write_str(self.as_str())
509    }
510}
511
512impl AsRef<str> for AnalyticNumberState {
513    fn as_ref(&self) -> &str {
514        self.as_str()
515    }
516}
517
518#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
519#[non_exhaustive]
520pub struct ApiDiscovery {
521    /// Canonical API origin for public V1 requests.
522    pub api_base_url: String,
523    /// Full agent-readable API reference.
524    pub docs_url: String,
525    /// Canonical web-origin OpenAPI JSON document.
526    pub openapi_url: String,
527    /// Unauthenticated API health endpoint.
528    pub health_url: String,
529    pub authentication: String,
530    /// 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.
531    pub protected_resource_metadata_url: String,
532    /// 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.
533    pub authenticated_routes: Vec<String>,
534}
535
536#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
537#[non_exhaustive]
538pub struct ApiError {
539    pub object: String,
540    pub error: ApiErrorError,
541    pub meta: ResponseMeta,
542}
543
544#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
545#[non_exhaustive]
546pub struct ApiErrorBody {
547    /// 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.
548    pub code: ErrorCode,
549    pub message: String,
550    #[serde(default, skip_serializing_if = "Option::is_none")]
551    pub doc_url: Option<String>,
552    #[serde(default, skip_serializing_if = "Option::is_none")]
553    pub param: Option<String>,
554    /// 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.
555    #[serde(default, skip_serializing_if = "Option::is_none")]
556    pub retry_at: Option<String>,
557    #[serde(default, skip_serializing_if = "Option::is_none")]
558    pub freshness: Option<FreshnessFailure>,
559    /// 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.
560    #[serde(default, skip_serializing_if = "Option::is_none")]
561    pub billing_url: Option<String>,
562    /// ADDITIVE (#7209). The specific, actionable cause behind `code`, when there is one more specific than the code itself. `code` keeps its published values, so existing clients are unaffected; new clients branch on `reason`. Omitted when the code already says everything we know. pick_not_released: no Pick of the Day is published for the current product day; schedule one request against retry_at instead of polling. unknown_endpoint: the PATH is not a route on this API -- read GET /api/v1, do not retry. trader_not_tracked: the wallet is real and the URL is right, but the trader is not on the warm sync tier (the wallets we sync most often) -- stop asking for this wallet. market_out_of_scope (404 not_found, #27303): the market or event is real and the URL is right, but 0xinsider serves sports and esports markets only -- stop asking for this market; neither a retry nor another URL for it can succeed. cursor_expired: pagination went stale mid-walk -- re-request the first page and continue. read_model_warming: the requested endpoint cannot serve its read model yet; exact causes are endpoint-specific and can include a cold or contended refresh or a dependency that prevented refresh. database_unavailable: the API's database or its connection pool is temporarily unreachable (a connection-class failure, not a query fault); code stays rate_limit_unavailable, nothing is rate-limited, retry after Retry-After / retry_at. idempotency_in_progress: retain the exact Idempotency-Key and request body, then retry shortly. webhook_delivery_in_progress: retry the URL or signing-secret configuration change after the destination's active request completes. request_accounting_unavailable: accounting capacity is unavailable before the handler executes; retry after Retry-After / retry_at. sandbox_api_key: the credential is a sandbox key (oxi_sk_test_) from POST /api/v1/agents/register, which only the sandbox server accepts -- call the sandbox base URL with it, or get a live key or OAuth access token; do not retry it here. api_key_in_query: the key was sent as a ?token= query parameter, which no route reads because URLs land in logs and history; the key itself was not checked -- resend it as Authorization: Bearer. subscription_inactive: the key is valid but the account's Pro subscription has lapsed (402 subscription_required); permanent until a person reactivates at https://0xinsider.com/billing, which the message names -- stop retrying on a schedule and surface the link. The key owner is emailed once per lapse. payment_overdue (402 subscription_required, #32592): the key is valid and the account still has its plan, but its latest subscription invoice is unpaid (Stripe past_due or unpaid), so paid access is paused; permanent until a person pays at billing_url (https://0xinsider.com/billing) -- stop retrying on a schedule and surface the link. The key works again the moment the invoice is paid. GET /api/v1/me and GET /api/v1/usage keep answering. monthly_quota_exceeded: the account has used the requests its plan includes for the UTC calendar month (429 rate_limited); retry_at and Retry-After name the first of next month, the only retry that can succeed, and the message names https://0xinsider.com/developers, where pay as you go for requests over the quota is turned on. The X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining and X-Monthly-Quota-Reset headers on every authenticated response say how close the account is. invalid_query, invalid_path, invalid_body (400 bad_request, #16146): a query parameter, a path segment or the JSON body did not parse or does not fit the route's schema, so no handler ran; param names the field when the parser named one (a query key, a path segment, a JSON path such as traders[0], or body); fix the request, never retry it as sent. unsupported_media_type (415 bad_request, param content-type): send the body with Content-Type: application/json. payload_too_large (413 bad_request, param body): the body is over 1048576 bytes. method_not_allowed (405 bad_request): the path is a route but not with this method; the Allow header names the methods it serves. ip_rate_limited (429 rate_limited, #16380): the per-address budget every caller behind one IP shares, counted before authentication, is spent; not the key's own window, and the RateLimit-* headers describe that bucket. ip_throttled (429 rate_limited): the address is in a cooldown after sustained over-limit traffic; Retry-After is minutes to days, and a request before it does not shorten the cooldown. cold_read_limited (429 rate_limited, #28752): the account has used its share of cold reads on GET /api/v1/market/{condition_id}/holders, requests for a market whose roster is not cached, each of which walks Polymarket (6 a minute, in bursts of up to 400); not the per-minute window, so a cached market still answers, and the next cold read is admitted at Retry-After. max_plan_required (403 forbidden, #23085): the key is valid and its account is on Pro, but the route is part of Max (GET /api/v1/edge-hunter); every Pro route keeps working with the same key, so do not disable it. The message names https://0xinsider.com/pricing, where the account upgrades; a retry never clears it. endpoint_retired (410): this legacy sports endpoint no longer serves data. Migrate to GET /api/v1/edge-hunter; retrying the retired path cannot succeed.
563    #[serde(default, skip_serializing_if = "Option::is_none")]
564    pub reason: Option<ErrorReason>,
565}
566
567#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
568#[non_exhaustive]
569pub struct ApiErrorError {
570    /// 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.
571    pub code: ErrorCode,
572    pub message: String,
573    #[serde(default, skip_serializing_if = "Option::is_none")]
574    pub doc_url: Option<String>,
575    #[serde(default, skip_serializing_if = "Option::is_none")]
576    pub param: Option<String>,
577    /// 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.
578    #[serde(default, skip_serializing_if = "Option::is_none")]
579    pub retry_at: Option<String>,
580    #[serde(default, skip_serializing_if = "Option::is_none")]
581    pub freshness: Option<FreshnessFailure>,
582    /// 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.
583    #[serde(default, skip_serializing_if = "Option::is_none")]
584    pub billing_url: Option<String>,
585    /// ADDITIVE (#7209). The specific, actionable cause behind `code`, when there is one more specific than the code itself. `code` keeps its published values, so existing clients are unaffected; new clients branch on `reason`. Omitted when the code already says everything we know. pick_not_released: no Pick of the Day is published for the current product day; schedule one request against retry_at instead of polling. unknown_endpoint: the PATH is not a route on this API -- read GET /api/v1, do not retry. trader_not_tracked: the wallet is real and the URL is right, but the trader is not on the warm sync tier (the wallets we sync most often) -- stop asking for this wallet. market_out_of_scope (404 not_found, #27303): the market or event is real and the URL is right, but 0xinsider serves sports and esports markets only -- stop asking for this market; neither a retry nor another URL for it can succeed. cursor_expired: pagination went stale mid-walk -- re-request the first page and continue. read_model_warming: the requested endpoint cannot serve its read model yet; exact causes are endpoint-specific and can include a cold or contended refresh or a dependency that prevented refresh. database_unavailable: the API's database or its connection pool is temporarily unreachable (a connection-class failure, not a query fault); code stays rate_limit_unavailable, nothing is rate-limited, retry after Retry-After / retry_at. idempotency_in_progress: retain the exact Idempotency-Key and request body, then retry shortly. webhook_delivery_in_progress: retry the URL or signing-secret configuration change after the destination's active request completes. request_accounting_unavailable: accounting capacity is unavailable before the handler executes; retry after Retry-After / retry_at. sandbox_api_key: the credential is a sandbox key (oxi_sk_test_) from POST /api/v1/agents/register, which only the sandbox server accepts -- call the sandbox base URL with it, or get a live key or OAuth access token; do not retry it here. api_key_in_query: the key was sent as a ?token= query parameter, which no route reads because URLs land in logs and history; the key itself was not checked -- resend it as Authorization: Bearer. subscription_inactive: the key is valid but the account's Pro subscription has lapsed (402 subscription_required); permanent until a person reactivates at https://0xinsider.com/billing, which the message names -- stop retrying on a schedule and surface the link. The key owner is emailed once per lapse. payment_overdue (402 subscription_required, #32592): the key is valid and the account still has its plan, but its latest subscription invoice is unpaid (Stripe past_due or unpaid), so paid access is paused; permanent until a person pays at billing_url (https://0xinsider.com/billing) -- stop retrying on a schedule and surface the link. The key works again the moment the invoice is paid. GET /api/v1/me and GET /api/v1/usage keep answering. monthly_quota_exceeded: the account has used the requests its plan includes for the UTC calendar month (429 rate_limited); retry_at and Retry-After name the first of next month, the only retry that can succeed, and the message names https://0xinsider.com/developers, where pay as you go for requests over the quota is turned on. The X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining and X-Monthly-Quota-Reset headers on every authenticated response say how close the account is. invalid_query, invalid_path, invalid_body (400 bad_request, #16146): a query parameter, a path segment or the JSON body did not parse or does not fit the route's schema, so no handler ran; param names the field when the parser named one (a query key, a path segment, a JSON path such as traders[0], or body); fix the request, never retry it as sent. unsupported_media_type (415 bad_request, param content-type): send the body with Content-Type: application/json. payload_too_large (413 bad_request, param body): the body is over 1048576 bytes. method_not_allowed (405 bad_request): the path is a route but not with this method; the Allow header names the methods it serves. ip_rate_limited (429 rate_limited, #16380): the per-address budget every caller behind one IP shares, counted before authentication, is spent; not the key's own window, and the RateLimit-* headers describe that bucket. ip_throttled (429 rate_limited): the address is in a cooldown after sustained over-limit traffic; Retry-After is minutes to days, and a request before it does not shorten the cooldown. cold_read_limited (429 rate_limited, #28752): the account has used its share of cold reads on GET /api/v1/market/{condition_id}/holders, requests for a market whose roster is not cached, each of which walks Polymarket (6 a minute, in bursts of up to 400); not the per-minute window, so a cached market still answers, and the next cold read is admitted at Retry-After. max_plan_required (403 forbidden, #23085): the key is valid and its account is on Pro, but the route is part of Max (GET /api/v1/edge-hunter); every Pro route keeps working with the same key, so do not disable it. The message names https://0xinsider.com/pricing, where the account upgrades; a retry never clears it. endpoint_retired (410): this legacy sports endpoint no longer serves data. Migrate to GET /api/v1/edge-hunter; retrying the retired path cannot succeed.
586    #[serde(default, skip_serializing_if = "Option::is_none")]
587    pub reason: Option<ErrorReason>,
588}
589
590/// A value this release does not know is kept in `Other`, so a new value never fails a response.
591#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
592#[non_exhaustive]
593pub enum Basis {
594    /// `game_lines`
595    #[serde(rename = "game_lines")]
596    GameLines,
597    /// `event_total`
598    #[serde(rename = "event_total")]
599    EventTotal,
600    /// A value this release does not know, kept as sent.
601    #[serde(untagged)]
602    Other(String),
603}
604
605impl Basis {
606    /// The value as the API spells it.
607    pub fn as_str(&self) -> &str {
608        match self {
609            Self::GameLines => "game_lines",
610            Self::EventTotal => "event_total",
611            Self::Other(value) => value,
612        }
613    }
614}
615
616impl From<&str> for Basis {
617    fn from(value: &str) -> Self {
618        match value {
619            "game_lines" => Self::GameLines,
620            "event_total" => Self::EventTotal,
621            other => Self::Other(other.to_owned()),
622        }
623    }
624}
625
626impl std::fmt::Display for Basis {
627    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
628        f.write_str(self.as_str())
629    }
630}
631
632impl AsRef<str> for Basis {
633    fn as_ref(&self) -> &str {
634        self.as_str()
635    }
636}
637
638#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
639#[non_exhaustive]
640pub struct BatchGameHoldersItem {
641    /// Zero-based request index. Duplicate inputs keep separate result rows.
642    pub index: i64,
643    pub input: String,
644    pub status: BatchTraderItemStatus,
645    #[serde(default, skip_serializing_if = "Option::is_none")]
646    pub data: Option<GameHoldersItem>,
647    #[serde(default, skip_serializing_if = "Option::is_none")]
648    pub error: Option<ApiErrorBody>,
649}
650
651#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
652pub struct BatchGetMarketFlowBody {
653    /// Market condition IDs to resolve in input order.
654    pub condition_ids: Vec<String>,
655    /// Lookback window used for flow and trade-count context.
656    #[serde(default, skip_serializing_if = "Option::is_none")]
657    pub timeframe: Option<Timeframe>,
658}
659
660#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
661#[non_exhaustive]
662pub struct BatchGetMarketFlowResponse {
663    pub object: String,
664    pub data: Vec<BatchMarketFlowItem>,
665    pub meta: BatchResponseMeta,
666}
667
668#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
669pub struct BatchGetMarketIntelBody {
670    /// Market condition IDs to resolve in input order.
671    pub condition_ids: Vec<String>,
672    /// Lookback window used for flow and trade-count context.
673    #[serde(default, skip_serializing_if = "Option::is_none")]
674    pub timeframe: Option<Timeframe>,
675}
676
677#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
678#[non_exhaustive]
679pub struct BatchGetMarketIntelResponse {
680    pub object: String,
681    pub data: Vec<BatchMarketFlowItem>,
682    pub meta: BatchResponseMeta,
683}
684
685#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
686pub struct BatchGetTradersBody {
687    /// Trader identities to resolve in input order.
688    pub traders: Vec<String>,
689    /// 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.
690    #[serde(default, skip_serializing_if = "Option::is_none")]
691    pub expand: Option<Vec<BatchGetTradersBodyExpand>>,
692}
693
694/// A value this release does not know is kept in `Other`, so a new value never fails a response.
695#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
696#[non_exhaustive]
697pub enum BatchGetTradersBodyExpand {
698    /// `strategy`
699    #[serde(rename = "strategy")]
700    Strategy,
701    /// `categories`
702    #[serde(rename = "categories")]
703    Categories,
704    /// `quant_metrics`
705    #[serde(rename = "quant_metrics")]
706    QuantMetrics,
707    /// `trust`
708    #[serde(rename = "trust")]
709    Trust,
710    /// A value this release does not know, kept as sent.
711    #[serde(untagged)]
712    Other(String),
713}
714
715impl BatchGetTradersBodyExpand {
716    /// The value as the API spells it.
717    pub fn as_str(&self) -> &str {
718        match self {
719            Self::Strategy => "strategy",
720            Self::Categories => "categories",
721            Self::QuantMetrics => "quant_metrics",
722            Self::Trust => "trust",
723            Self::Other(value) => value,
724        }
725    }
726}
727
728impl From<&str> for BatchGetTradersBodyExpand {
729    fn from(value: &str) -> Self {
730        match value {
731            "strategy" => Self::Strategy,
732            "categories" => Self::Categories,
733            "quant_metrics" => Self::QuantMetrics,
734            "trust" => Self::Trust,
735            other => Self::Other(other.to_owned()),
736        }
737    }
738}
739
740impl std::fmt::Display for BatchGetTradersBodyExpand {
741    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
742        f.write_str(self.as_str())
743    }
744}
745
746impl AsRef<str> for BatchGetTradersBodyExpand {
747    fn as_ref(&self) -> &str {
748        self.as_str()
749    }
750}
751
752#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
753#[non_exhaustive]
754pub struct BatchGetTradersResponse {
755    pub object: String,
756    pub data: Vec<BatchTraderItem>,
757    pub meta: BatchResponseMeta,
758}
759
760#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
761#[non_exhaustive]
762pub struct BatchMarketFlowItem {
763    /// Zero-based request index. Duplicate inputs keep separate result rows.
764    pub index: i64,
765    pub input: String,
766    pub status: BatchTraderItemStatus,
767    #[serde(default, skip_serializing_if = "Option::is_none")]
768    pub data: Option<MarketFlow>,
769    #[serde(default, skip_serializing_if = "Option::is_none")]
770    pub error: Option<ApiErrorBody>,
771}
772
773#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
774#[non_exhaustive]
775pub struct BatchRateLimitMeta {
776    pub basis: String,
777    /// 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.
778    pub limit: i64,
779    pub remaining: i64,
780    /// Unix timestamp when the batch item window resets.
781    pub reset: i64,
782}
783
784#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
785#[non_exhaustive]
786pub struct BatchResponseMeta {
787    /// 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.
788    pub request_id: String,
789    pub cached: bool,
790    pub total_items: i64,
791    pub successful_items: i64,
792    pub failed_items: i64,
793    /// Number of batch item units reserved before execution.
794    pub request_cost: i64,
795    pub rate_limit: BatchRateLimitMeta,
796}
797
798#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
799#[non_exhaustive]
800pub struct BatchTraderItem {
801    /// Zero-based request index. Duplicate inputs keep separate result rows.
802    pub index: i64,
803    pub input: String,
804    pub status: BatchTraderItemStatus,
805    #[serde(default, skip_serializing_if = "Option::is_none")]
806    pub data: Option<Trader>,
807    #[serde(default, skip_serializing_if = "Option::is_none")]
808    pub error: Option<ApiErrorBody>,
809}
810
811/// A value this release does not know is kept in `Other`, so a new value never fails a response.
812#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
813#[non_exhaustive]
814pub enum BatchTraderItemStatus {
815    /// `ok`
816    #[serde(rename = "ok")]
817    Ok,
818    /// `error`
819    #[serde(rename = "error")]
820    Error,
821    /// A value this release does not know, kept as sent.
822    #[serde(untagged)]
823    Other(String),
824}
825
826impl BatchTraderItemStatus {
827    /// The value as the API spells it.
828    pub fn as_str(&self) -> &str {
829        match self {
830            Self::Ok => "ok",
831            Self::Error => "error",
832            Self::Other(value) => value,
833        }
834    }
835}
836
837impl From<&str> for BatchTraderItemStatus {
838    fn from(value: &str) -> Self {
839        match value {
840            "ok" => Self::Ok,
841            "error" => Self::Error,
842            other => Self::Other(other.to_owned()),
843        }
844    }
845}
846
847impl std::fmt::Display for BatchTraderItemStatus {
848    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
849        f.write_str(self.as_str())
850    }
851}
852
853impl AsRef<str> for BatchTraderItemStatus {
854    fn as_ref(&self) -> &str {
855        self.as_str()
856    }
857}
858
859/// A value this release does not know is kept in `Other`, so a new value never fails a response.
860#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
861#[non_exhaustive]
862pub enum BoardUpcomingStatus {
863    /// `unknown`
864    #[serde(rename = "unknown")]
865    Unknown,
866    /// `not_configured`
867    #[serde(rename = "not_configured")]
868    NotConfigured,
869    /// `available`
870    #[serde(rename = "available")]
871    Available,
872    /// `capacity_limited`
873    #[serde(rename = "capacity_limited")]
874    CapacityLimited,
875    /// `source_unavailable`
876    #[serde(rename = "source_unavailable")]
877    SourceUnavailable,
878    /// `cold_unavailable`
879    #[serde(rename = "cold_unavailable")]
880    ColdUnavailable,
881    /// `deadline_unavailable`
882    #[serde(rename = "deadline_unavailable")]
883    DeadlineUnavailable,
884    /// A value this release does not know, kept as sent.
885    #[serde(untagged)]
886    Other(String),
887}
888
889impl BoardUpcomingStatus {
890    /// The value as the API spells it.
891    pub fn as_str(&self) -> &str {
892        match self {
893            Self::Unknown => "unknown",
894            Self::NotConfigured => "not_configured",
895            Self::Available => "available",
896            Self::CapacityLimited => "capacity_limited",
897            Self::SourceUnavailable => "source_unavailable",
898            Self::ColdUnavailable => "cold_unavailable",
899            Self::DeadlineUnavailable => "deadline_unavailable",
900            Self::Other(value) => value,
901        }
902    }
903}
904
905impl From<&str> for BoardUpcomingStatus {
906    fn from(value: &str) -> Self {
907        match value {
908            "unknown" => Self::Unknown,
909            "not_configured" => Self::NotConfigured,
910            "available" => Self::Available,
911            "capacity_limited" => Self::CapacityLimited,
912            "source_unavailable" => Self::SourceUnavailable,
913            "cold_unavailable" => Self::ColdUnavailable,
914            "deadline_unavailable" => Self::DeadlineUnavailable,
915            other => Self::Other(other.to_owned()),
916        }
917    }
918}
919
920impl std::fmt::Display for BoardUpcomingStatus {
921    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
922        f.write_str(self.as_str())
923    }
924}
925
926impl AsRef<str> for BoardUpcomingStatus {
927    fn as_ref(&self) -> &str {
928        self.as_str()
929    }
930}
931
932/// A value this release does not know is kept in `Other`, so a new value never fails a response.
933#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
934#[non_exhaustive]
935pub enum BoardUpcomingUnavailableScopes {
936    /// `category`
937    #[serde(rename = "category")]
938    Category,
939    /// `nfl`
940    #[serde(rename = "nfl")]
941    Nfl,
942    /// `cfb`
943    #[serde(rename = "cfb")]
944    Cfb,
945    /// `nba`
946    #[serde(rename = "nba")]
947    Nba,
948    /// `wnba`
949    #[serde(rename = "wnba")]
950    Wnba,
951    /// `euroleague-basketball`
952    #[serde(rename = "euroleague-basketball")]
953    EuroleagueBasketball,
954    /// `ncaa-basketball`
955    #[serde(rename = "ncaa-basketball")]
956    NcaaBasketball,
957    /// `cwbb`
958    #[serde(rename = "cwbb")]
959    Cwbb,
960    /// `nhl`
961    #[serde(rename = "nhl")]
962    Nhl,
963    /// `mls`
964    #[serde(rename = "mls")]
965    Mls,
966    /// `valorant`
967    #[serde(rename = "valorant")]
968    Valorant,
969    /// `league-of-legends`
970    #[serde(rename = "league-of-legends")]
971    LeagueOfLegends,
972    /// `counter-strike-2`
973    #[serde(rename = "counter-strike-2")]
974    CounterStrike2,
975    /// `dota-2`
976    #[serde(rename = "dota-2")]
977    Dota2,
978    /// `registry`
979    #[serde(rename = "registry")]
980    Registry,
981    /// `union`
982    #[serde(rename = "union")]
983    Union,
984    /// `wave`
985    #[serde(rename = "wave")]
986    Wave,
987    /// A value this release does not know, kept as sent.
988    #[serde(untagged)]
989    Other(String),
990}
991
992impl BoardUpcomingUnavailableScopes {
993    /// The value as the API spells it.
994    pub fn as_str(&self) -> &str {
995        match self {
996            Self::Category => "category",
997            Self::Nfl => "nfl",
998            Self::Cfb => "cfb",
999            Self::Nba => "nba",
1000            Self::Wnba => "wnba",
1001            Self::EuroleagueBasketball => "euroleague-basketball",
1002            Self::NcaaBasketball => "ncaa-basketball",
1003            Self::Cwbb => "cwbb",
1004            Self::Nhl => "nhl",
1005            Self::Mls => "mls",
1006            Self::Valorant => "valorant",
1007            Self::LeagueOfLegends => "league-of-legends",
1008            Self::CounterStrike2 => "counter-strike-2",
1009            Self::Dota2 => "dota-2",
1010            Self::Registry => "registry",
1011            Self::Union => "union",
1012            Self::Wave => "wave",
1013            Self::Other(value) => value,
1014        }
1015    }
1016}
1017
1018impl From<&str> for BoardUpcomingUnavailableScopes {
1019    fn from(value: &str) -> Self {
1020        match value {
1021            "category" => Self::Category,
1022            "nfl" => Self::Nfl,
1023            "cfb" => Self::Cfb,
1024            "nba" => Self::Nba,
1025            "wnba" => Self::Wnba,
1026            "euroleague-basketball" => Self::EuroleagueBasketball,
1027            "ncaa-basketball" => Self::NcaaBasketball,
1028            "cwbb" => Self::Cwbb,
1029            "nhl" => Self::Nhl,
1030            "mls" => Self::Mls,
1031            "valorant" => Self::Valorant,
1032            "league-of-legends" => Self::LeagueOfLegends,
1033            "counter-strike-2" => Self::CounterStrike2,
1034            "dota-2" => Self::Dota2,
1035            "registry" => Self::Registry,
1036            "union" => Self::Union,
1037            "wave" => Self::Wave,
1038            other => Self::Other(other.to_owned()),
1039        }
1040    }
1041}
1042
1043impl std::fmt::Display for BoardUpcomingUnavailableScopes {
1044    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1045        f.write_str(self.as_str())
1046    }
1047}
1048
1049impl AsRef<str> for BoardUpcomingUnavailableScopes {
1050    fn as_ref(&self) -> &str {
1051        self.as_str()
1052    }
1053}
1054
1055/// One bucketed OHLC price candle. Prices are in provider [0, 1] units, truncated to 4 decimals at the rendering edge.
1056#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1057#[non_exhaustive]
1058pub struct Candle {
1059    /// Bucket-start unix epoch (seconds): UTC midnight for 1d, the ISO-week Monday's UTC midnight for 1w.
1060    pub t: i64,
1061    /// Open price in provider [0, 1] units (first observed point in the bucket).
1062    pub o: f64,
1063    /// High price in provider [0, 1] units (max observed in the bucket).
1064    pub h: f64,
1065    /// Low price in provider [0, 1] units (min observed in the bucket).
1066    pub l: f64,
1067    /// Close price in provider [0, 1] units (last observed point in the bucket).
1068    pub c: f64,
1069}
1070
1071/// A value this release does not know is kept in `Other`, so a new value never fails a response.
1072#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1073#[non_exhaustive]
1074pub enum Category {
1075    /// `Basketball`
1076    #[serde(rename = "Basketball")]
1077    Basketball,
1078    /// `Football`
1079    #[serde(rename = "Football")]
1080    Football,
1081    /// `Baseball`
1082    #[serde(rename = "Baseball")]
1083    Baseball,
1084    /// `Hockey`
1085    #[serde(rename = "Hockey")]
1086    Hockey,
1087    /// `MMA`
1088    #[serde(rename = "MMA")]
1089    Mma,
1090    /// `Boxing`
1091    #[serde(rename = "Boxing")]
1092    Boxing,
1093    /// `Soccer`
1094    #[serde(rename = "Soccer")]
1095    Soccer,
1096    /// `Cricket`
1097    #[serde(rename = "Cricket")]
1098    Cricket,
1099    /// `Golf`
1100    #[serde(rename = "Golf")]
1101    Golf,
1102    /// `Tennis`
1103    #[serde(rename = "Tennis")]
1104    Tennis,
1105    /// `Esports`
1106    #[serde(rename = "Esports")]
1107    Esports,
1108    /// `Racing`
1109    #[serde(rename = "Racing")]
1110    Racing,
1111    /// `Table Tennis`
1112    #[serde(rename = "Table Tennis")]
1113    TableTennis,
1114    /// `Pickleball`
1115    #[serde(rename = "Pickleball")]
1116    Pickleball,
1117    /// A value this release does not know, kept as sent.
1118    #[serde(untagged)]
1119    Other(String),
1120}
1121
1122impl Category {
1123    /// The value as the API spells it.
1124    pub fn as_str(&self) -> &str {
1125        match self {
1126            Self::Basketball => "Basketball",
1127            Self::Football => "Football",
1128            Self::Baseball => "Baseball",
1129            Self::Hockey => "Hockey",
1130            Self::Mma => "MMA",
1131            Self::Boxing => "Boxing",
1132            Self::Soccer => "Soccer",
1133            Self::Cricket => "Cricket",
1134            Self::Golf => "Golf",
1135            Self::Tennis => "Tennis",
1136            Self::Esports => "Esports",
1137            Self::Racing => "Racing",
1138            Self::TableTennis => "Table Tennis",
1139            Self::Pickleball => "Pickleball",
1140            Self::Other(value) => value,
1141        }
1142    }
1143}
1144
1145impl From<&str> for Category {
1146    fn from(value: &str) -> Self {
1147        match value {
1148            "Basketball" => Self::Basketball,
1149            "Football" => Self::Football,
1150            "Baseball" => Self::Baseball,
1151            "Hockey" => Self::Hockey,
1152            "MMA" => Self::Mma,
1153            "Boxing" => Self::Boxing,
1154            "Soccer" => Self::Soccer,
1155            "Cricket" => Self::Cricket,
1156            "Golf" => Self::Golf,
1157            "Tennis" => Self::Tennis,
1158            "Esports" => Self::Esports,
1159            "Racing" => Self::Racing,
1160            "Table Tennis" => Self::TableTennis,
1161            "Pickleball" => Self::Pickleball,
1162            other => Self::Other(other.to_owned()),
1163        }
1164    }
1165}
1166
1167impl std::fmt::Display for Category {
1168    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1169        f.write_str(self.as_str())
1170    }
1171}
1172
1173impl AsRef<str> for Category {
1174    fn as_ref(&self) -> &str {
1175        self.as_str()
1176    }
1177}
1178
1179#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1180#[non_exhaustive]
1181pub struct CategoryLeader {
1182    pub address: String,
1183    pub as_of: String,
1184    pub category: String,
1185    #[serde(default)]
1186    pub edge_lower_bound: Option<f64>,
1187    #[serde(default)]
1188    pub grade: Option<Grade>,
1189    pub id: String,
1190    pub independent_events: i64,
1191    #[serde(default)]
1192    pub n_resolved: Option<i64>,
1193    pub platform: String,
1194    #[serde(default)]
1195    pub pnl: Option<f64>,
1196    pub rank: i64,
1197    pub unresolved_events: i64,
1198    #[serde(default)]
1199    pub username: Option<String>,
1200    #[serde(default)]
1201    pub win_rate: Option<f64>,
1202}
1203
1204/// Model-wide readiness, read in the same database snapshot as category_records. Individual category rows retain their own status.
1205#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1206#[non_exhaustive]
1207pub struct CategorySkillModelReadiness {
1208    pub status: Status,
1209    pub model_version: String,
1210    pub taxonomy_version: String,
1211    pub observation_started_at: String,
1212    pub as_of: String,
1213    #[serde(default)]
1214    pub source_last_success_at: Option<String>,
1215}
1216
1217/// A value this release does not know is kept in `Other`, so a new value never fails a response.
1218#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1219#[non_exhaustive]
1220pub enum CategorySkillSource {
1221    /// `live`
1222    #[serde(rename = "live")]
1223    Live,
1224    /// `partial`
1225    #[serde(rename = "partial")]
1226    Partial,
1227    /// `degraded`
1228    #[serde(rename = "degraded")]
1229    Degraded,
1230    /// `unavailable`
1231    #[serde(rename = "unavailable")]
1232    Unavailable,
1233    /// A value this release does not know, kept as sent.
1234    #[serde(untagged)]
1235    Other(String),
1236}
1237
1238impl CategorySkillSource {
1239    /// The value as the API spells it.
1240    pub fn as_str(&self) -> &str {
1241        match self {
1242            Self::Live => "live",
1243            Self::Partial => "partial",
1244            Self::Degraded => "degraded",
1245            Self::Unavailable => "unavailable",
1246            Self::Other(value) => value,
1247        }
1248    }
1249}
1250
1251impl From<&str> for CategorySkillSource {
1252    fn from(value: &str) -> Self {
1253        match value {
1254            "live" => Self::Live,
1255            "partial" => Self::Partial,
1256            "degraded" => Self::Degraded,
1257            "unavailable" => Self::Unavailable,
1258            other => Self::Other(other.to_owned()),
1259        }
1260    }
1261}
1262
1263impl std::fmt::Display for CategorySkillSource {
1264    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1265        f.write_str(self.as_str())
1266    }
1267}
1268
1269impl AsRef<str> for CategorySkillSource {
1270    fn as_ref(&self) -> &str {
1271        self.as_str()
1272    }
1273}
1274
1275/// 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.
1276#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1277#[non_exhaustive]
1278pub struct CategorySkillV2 {
1279    pub status: Status,
1280    pub model_version: String,
1281    #[serde(default)]
1282    pub taxonomy_version: Option<String>,
1283    pub platform: String,
1284    pub scope: String,
1285    pub source_coverage: SourceCoverage,
1286    pub canonical_category: String,
1287    pub as_of: String,
1288    #[serde(default)]
1289    pub source_last_success_at: Option<String>,
1290    pub observation_started_at: String,
1291    #[serde(default)]
1292    pub latest_observation_at: Option<String>,
1293    pub independent_event_count: i64,
1294    pub resolved_condition_count: i64,
1295    pub unresolved_observation_count: i64,
1296    #[serde(default)]
1297    pub edge_mean: Option<f64>,
1298    #[serde(default)]
1299    pub edge_sd: Option<f64>,
1300    #[serde(default)]
1301    pub edge_se: Option<f64>,
1302    #[serde(default)]
1303    pub edge_lower_95: Option<f64>,
1304    #[serde(default)]
1305    pub brier_event_avg: Option<f64>,
1306}
1307
1308/// A value this release does not know is kept in `Other`, so a new value never fails a response.
1309#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1310#[non_exhaustive]
1311pub enum CategoryWinRateStatus {
1312    /// `measured`
1313    #[serde(rename = "measured")]
1314    Measured,
1315    /// `not_enough_data`
1316    #[serde(rename = "not_enough_data")]
1317    NotEnoughData,
1318    /// `unavailable`
1319    #[serde(rename = "unavailable")]
1320    Unavailable,
1321    /// `untracked`
1322    #[serde(rename = "untracked")]
1323    Untracked,
1324    /// A value this release does not know, kept as sent.
1325    #[serde(untagged)]
1326    Other(String),
1327}
1328
1329impl CategoryWinRateStatus {
1330    /// The value as the API spells it.
1331    pub fn as_str(&self) -> &str {
1332        match self {
1333            Self::Measured => "measured",
1334            Self::NotEnoughData => "not_enough_data",
1335            Self::Unavailable => "unavailable",
1336            Self::Untracked => "untracked",
1337            Self::Other(value) => value,
1338        }
1339    }
1340}
1341
1342impl From<&str> for CategoryWinRateStatus {
1343    fn from(value: &str) -> Self {
1344        match value {
1345            "measured" => Self::Measured,
1346            "not_enough_data" => Self::NotEnoughData,
1347            "unavailable" => Self::Unavailable,
1348            "untracked" => Self::Untracked,
1349            other => Self::Other(other.to_owned()),
1350        }
1351    }
1352}
1353
1354impl std::fmt::Display for CategoryWinRateStatus {
1355    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1356        f.write_str(self.as_str())
1357    }
1358}
1359
1360impl AsRef<str> for CategoryWinRateStatus {
1361    fn as_ref(&self) -> &str {
1362        self.as_str()
1363    }
1364}
1365
1366/// A value this release does not know is kept in `Other`, so a new value never fails a response.
1367#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1368#[non_exhaustive]
1369pub enum Changed {
1370    /// `scores`
1371    #[serde(rename = "scores")]
1372    Scores,
1373    /// `status`
1374    #[serde(rename = "status")]
1375    Status,
1376    /// `period`
1377    #[serde(rename = "period")]
1378    Period,
1379    /// `live`
1380    #[serde(rename = "live")]
1381    Live,
1382    /// `ended`
1383    #[serde(rename = "ended")]
1384    Ended,
1385    /// A value this release does not know, kept as sent.
1386    #[serde(untagged)]
1387    Other(String),
1388}
1389
1390impl Changed {
1391    /// The value as the API spells it.
1392    pub fn as_str(&self) -> &str {
1393        match self {
1394            Self::Scores => "scores",
1395            Self::Status => "status",
1396            Self::Period => "period",
1397            Self::Live => "live",
1398            Self::Ended => "ended",
1399            Self::Other(value) => value,
1400        }
1401    }
1402}
1403
1404impl From<&str> for Changed {
1405    fn from(value: &str) -> Self {
1406        match value {
1407            "scores" => Self::Scores,
1408            "status" => Self::Status,
1409            "period" => Self::Period,
1410            "live" => Self::Live,
1411            "ended" => Self::Ended,
1412            other => Self::Other(other.to_owned()),
1413        }
1414    }
1415}
1416
1417impl std::fmt::Display for Changed {
1418    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1419        f.write_str(self.as_str())
1420    }
1421}
1422
1423impl AsRef<str> for Changed {
1424    fn as_ref(&self) -> &str {
1425        self.as_str()
1426    }
1427}
1428
1429/// A value this release does not know is kept in `Other`, so a new value never fails a response.
1430#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1431#[non_exhaustive]
1432pub enum ClvApplicability {
1433    /// `applicable`
1434    #[serde(rename = "applicable")]
1435    Applicable,
1436    /// `not_applicable`
1437    #[serde(rename = "not_applicable")]
1438    NotApplicable,
1439    /// A value this release does not know, kept as sent.
1440    #[serde(untagged)]
1441    Other(String),
1442}
1443
1444impl ClvApplicability {
1445    /// The value as the API spells it.
1446    pub fn as_str(&self) -> &str {
1447        match self {
1448            Self::Applicable => "applicable",
1449            Self::NotApplicable => "not_applicable",
1450            Self::Other(value) => value,
1451        }
1452    }
1453}
1454
1455impl From<&str> for ClvApplicability {
1456    fn from(value: &str) -> Self {
1457        match value {
1458            "applicable" => Self::Applicable,
1459            "not_applicable" => Self::NotApplicable,
1460            other => Self::Other(other.to_owned()),
1461        }
1462    }
1463}
1464
1465impl std::fmt::Display for ClvApplicability {
1466    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1467        f.write_str(self.as_str())
1468    }
1469}
1470
1471impl AsRef<str> for ClvApplicability {
1472    fn as_ref(&self) -> &str {
1473        self.as_str()
1474    }
1475}
1476
1477/// A value this release does not know is kept in `Other`, so a new value never fails a response.
1478#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1479#[non_exhaustive]
1480pub enum ClvState {
1481    /// `measured`
1482    #[serde(rename = "measured")]
1483    Measured,
1484    /// `pending`
1485    #[serde(rename = "pending")]
1486    Pending,
1487    /// `unavailable`
1488    #[serde(rename = "unavailable")]
1489    Unavailable,
1490    /// `not_applicable`
1491    #[serde(rename = "not_applicable")]
1492    NotApplicable,
1493    /// `none`
1494    #[serde(rename = "none")]
1495    None,
1496    /// A value this release does not know, kept as sent.
1497    #[serde(untagged)]
1498    Other(String),
1499}
1500
1501impl ClvState {
1502    /// The value as the API spells it.
1503    pub fn as_str(&self) -> &str {
1504        match self {
1505            Self::Measured => "measured",
1506            Self::Pending => "pending",
1507            Self::Unavailable => "unavailable",
1508            Self::NotApplicable => "not_applicable",
1509            Self::None => "none",
1510            Self::Other(value) => value,
1511        }
1512    }
1513}
1514
1515impl From<&str> for ClvState {
1516    fn from(value: &str) -> Self {
1517        match value {
1518            "measured" => Self::Measured,
1519            "pending" => Self::Pending,
1520            "unavailable" => Self::Unavailable,
1521            "not_applicable" => Self::NotApplicable,
1522            "none" => Self::None,
1523            other => Self::Other(other.to_owned()),
1524        }
1525    }
1526}
1527
1528impl std::fmt::Display for ClvState {
1529    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1530        f.write_str(self.as_str())
1531    }
1532}
1533
1534impl AsRef<str> for ClvState {
1535    fn as_ref(&self) -> &str {
1536        self.as_str()
1537    }
1538}
1539
1540/// A value this release does not know is kept in `Other`, so a new value never fails a response.
1541#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1542#[non_exhaustive]
1543pub enum Cohort {
1544    /// `wider_holder`
1545    #[serde(rename = "wider_holder")]
1546    WiderHolder,
1547    /// `in_play`
1548    #[serde(rename = "in_play")]
1549    InPlay,
1550    /// `emerging_pile`
1551    #[serde(rename = "emerging_pile")]
1552    EmergingPile,
1553    /// A value this release does not know, kept as sent.
1554    #[serde(untagged)]
1555    Other(String),
1556}
1557
1558impl Cohort {
1559    /// The value as the API spells it.
1560    pub fn as_str(&self) -> &str {
1561        match self {
1562            Self::WiderHolder => "wider_holder",
1563            Self::InPlay => "in_play",
1564            Self::EmergingPile => "emerging_pile",
1565            Self::Other(value) => value,
1566        }
1567    }
1568}
1569
1570impl From<&str> for Cohort {
1571    fn from(value: &str) -> Self {
1572        match value {
1573            "wider_holder" => Self::WiderHolder,
1574            "in_play" => Self::InPlay,
1575            "emerging_pile" => Self::EmergingPile,
1576            other => Self::Other(other.to_owned()),
1577        }
1578    }
1579}
1580
1581impl std::fmt::Display for Cohort {
1582    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1583        f.write_str(self.as_str())
1584    }
1585}
1586
1587impl AsRef<str> for Cohort {
1588    fn as_ref(&self) -> &str {
1589        self.as_str()
1590    }
1591}
1592
1593#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1594#[non_exhaustive]
1595pub struct Combo {
1596    /// Combo identifier: 0x followed by 62 lowercase hex characters. This differs from a binary market condition ID.
1597    pub condition_id: String,
1598    #[serde(default)]
1599    pub leg_count: Option<i64>,
1600    #[serde(default)]
1601    pub prepared_at: Option<String>,
1602    /// Whether the preparation event has been indexed.
1603    pub legs_known: bool,
1604    pub legs: Vec<ComboLeg>,
1605    #[serde(default)]
1606    pub window: Option<ComboWindowStats>,
1607    #[serde(default)]
1608    pub totals: Option<ComboTotals>,
1609    /// Result of the YES conjunction, independent of the wallet side or its P&L.
1610    pub status: ComboStatus,
1611    /// Reason the conjunction result cannot be verified, when unknown.
1612    #[serde(default)]
1613    pub status_reason: Option<String>,
1614}
1615
1616#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1617#[non_exhaustive]
1618pub struct ComboCoverage {
1619    pub state: ComboCoverageState,
1620    pub ingest_enabled: bool,
1621    pub cursors: Vec<ComboCoverageCursor>,
1622    #[serde(default)]
1623    pub max_lag_blocks: Option<i64>,
1624    #[serde(default)]
1625    pub oldest_cursor_update: Option<String>,
1626    #[serde(default)]
1627    pub lifecycle_lag_blocks: Option<i64>,
1628    pub lifecycle_backfilling: bool,
1629    /// Time the coverage state was evaluated; not a market-price timestamp.
1630    pub computed_at: String,
1631}
1632
1633#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1634#[non_exhaustive]
1635pub struct ComboCoverageCursor {
1636    /// Indexed contract.
1637    pub contract: String,
1638    pub last_block: i64,
1639    pub seed_block: i64,
1640    pub seed_origin: String,
1641    #[serde(default)]
1642    pub chain_finalized_block: Option<i64>,
1643    #[serde(default)]
1644    pub lag_blocks: Option<i64>,
1645    pub updated_at: String,
1646}
1647
1648/// A value this release does not know is kept in `Other`, so a new value never fails a response.
1649#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1650#[non_exhaustive]
1651pub enum ComboCoverageState {
1652    /// `paused`
1653    #[serde(rename = "paused")]
1654    Paused,
1655    /// `uninitialized`
1656    #[serde(rename = "uninitialized")]
1657    Uninitialized,
1658    /// `stale`
1659    #[serde(rename = "stale")]
1660    Stale,
1661    /// `backfilling`
1662    #[serde(rename = "backfilling")]
1663    Backfilling,
1664    /// `live`
1665    #[serde(rename = "live")]
1666    Live,
1667    /// A value this release does not know, kept as sent.
1668    #[serde(untagged)]
1669    Other(String),
1670}
1671
1672impl ComboCoverageState {
1673    /// The value as the API spells it.
1674    pub fn as_str(&self) -> &str {
1675        match self {
1676            Self::Paused => "paused",
1677            Self::Uninitialized => "uninitialized",
1678            Self::Stale => "stale",
1679            Self::Backfilling => "backfilling",
1680            Self::Live => "live",
1681            Self::Other(value) => value,
1682        }
1683    }
1684}
1685
1686impl From<&str> for ComboCoverageState {
1687    fn from(value: &str) -> Self {
1688        match value {
1689            "paused" => Self::Paused,
1690            "uninitialized" => Self::Uninitialized,
1691            "stale" => Self::Stale,
1692            "backfilling" => Self::Backfilling,
1693            "live" => Self::Live,
1694            other => Self::Other(other.to_owned()),
1695        }
1696    }
1697}
1698
1699impl std::fmt::Display for ComboCoverageState {
1700    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1701        f.write_str(self.as_str())
1702    }
1703}
1704
1705impl AsRef<str> for ComboCoverageState {
1706    fn as_ref(&self) -> &str {
1707        self.as_str()
1708    }
1709}
1710
1711/// One combo with its newest 100 fills and all-time lifecycle totals. Paid API callers receive full access.
1712#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1713#[non_exhaustive]
1714pub struct ComboDetail {
1715    pub access: String,
1716    pub combo: Combo,
1717    pub fills: Vec<ComboFill>,
1718    #[serde(default)]
1719    pub lifecycle: Option<ComboLifecycleStats>,
1720    pub coverage: ComboCoverage,
1721}
1722
1723#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1724#[non_exhaustive]
1725pub struct ComboFill {
1726    /// Stable fill identity.
1727    pub id: String,
1728    pub block_number: i64,
1729    pub log_index: i64,
1730    pub block_timestamp: String,
1731    pub tx_hash: String,
1732    /// Taker wallet address.
1733    #[serde(default)]
1734    pub trader: Option<String>,
1735    #[serde(default)]
1736    pub trader_name: Option<String>,
1737    #[serde(default)]
1738    pub trader_grade: Option<Grade>,
1739    /// Recorded wallet-wide trade time.
1740    #[serde(default)]
1741    pub last_traded_at: Option<String>,
1742    pub action: Action,
1743    /// Combo identifier: 0x followed by 62 lowercase hex characters. This differs from a binary market condition ID.
1744    pub condition_id: String,
1745    /// 0 is YES, 1 is NO.
1746    pub outcome_index: i64,
1747    /// Exact decimal string from the stored chain or SQL value; preserve precision until display.
1748    pub shares: String,
1749    /// Exact decimal string from the stored chain or SQL value; preserve precision until display.
1750    pub collateral_usdc: String,
1751    /// Execution price for the traded outcome; null for a zero-share event.
1752    #[serde(default)]
1753    pub price: Option<String>,
1754    /// Execution price normalized to YES.
1755    #[serde(default)]
1756    pub price_yes: Option<String>,
1757    /// Exact decimal string from the stored chain or SQL value; preserve precision until display.
1758    pub fee_usdc: String,
1759    #[serde(default)]
1760    pub leg_count: Option<i64>,
1761    /// Result of the YES conjunction, independent of the wallet side or its P&L.
1762    pub status: ComboStatus,
1763    #[serde(default)]
1764    pub status_reason: Option<String>,
1765    pub won_legs: i64,
1766    /// Shares per dollar at execution; not a forecast or guaranteed return.
1767    #[serde(default)]
1768    pub payout_multiplier: Option<String>,
1769    pub legs: Vec<ComboLeg>,
1770}
1771
1772#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1773#[non_exhaustive]
1774pub struct ComboFillsResponse {
1775    pub object: String,
1776    pub data: Vec<ComboFill>,
1777    pub sort: ComboFillsResponseSort,
1778    pub window: Window,
1779    pub limit: i64,
1780    pub coverage: ComboCoverage,
1781    /// A continuation is available based on page fullness. Its next page may be empty.
1782    pub has_more: bool,
1783    /// Exclusive block_number:log_index continuation for recent ordering.
1784    #[serde(default, skip_serializing_if = "Option::is_none")]
1785    pub next_cursor: Option<String>,
1786    /// Continuation offset for largest or payout ordering.
1787    #[serde(default, skip_serializing_if = "Option::is_none")]
1788    pub next_offset: Option<i64>,
1789    pub meta: ResponseMeta,
1790}
1791
1792/// A value this release does not know is kept in `Other`, so a new value never fails a response.
1793#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1794#[non_exhaustive]
1795pub enum ComboFillsResponseSort {
1796    /// `recent`
1797    #[serde(rename = "recent")]
1798    Recent,
1799    /// `largest`
1800    #[serde(rename = "largest")]
1801    Largest,
1802    /// `payout`
1803    #[serde(rename = "payout")]
1804    Payout,
1805    /// A value this release does not know, kept as sent.
1806    #[serde(untagged)]
1807    Other(String),
1808}
1809
1810impl ComboFillsResponseSort {
1811    /// The value as the API spells it.
1812    pub fn as_str(&self) -> &str {
1813        match self {
1814            Self::Recent => "recent",
1815            Self::Largest => "largest",
1816            Self::Payout => "payout",
1817            Self::Other(value) => value,
1818        }
1819    }
1820}
1821
1822impl From<&str> for ComboFillsResponseSort {
1823    fn from(value: &str) -> Self {
1824        match value {
1825            "recent" => Self::Recent,
1826            "largest" => Self::Largest,
1827            "payout" => Self::Payout,
1828            other => Self::Other(other.to_owned()),
1829        }
1830    }
1831}
1832
1833impl std::fmt::Display for ComboFillsResponseSort {
1834    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1835        f.write_str(self.as_str())
1836    }
1837}
1838
1839impl AsRef<str> for ComboFillsResponseSort {
1840    fn as_ref(&self) -> &str {
1841        self.as_str()
1842    }
1843}
1844
1845#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1846#[non_exhaustive]
1847pub struct ComboLeg {
1848    pub leg_index: i64,
1849    pub outcome_index: i64,
1850    pub module_id: i64,
1851    pub state: ComboLegState,
1852    #[serde(default)]
1853    pub market: Option<ComboLegMarket>,
1854}
1855
1856#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1857#[non_exhaustive]
1858pub struct ComboLegMarket {
1859    /// Source of the leg facts.
1860    pub source: ComboLegMarketSource,
1861    /// Full binary CTF condition ID for this leg.
1862    pub condition_id: String,
1863    #[serde(default)]
1864    pub title: Option<String>,
1865    #[serde(default)]
1866    pub slug: Option<String>,
1867    #[serde(default)]
1868    pub event_slug: Option<String>,
1869    /// Provider-resolved URL including the referral tag.
1870    #[serde(default, skip_serializing_if = "Option::is_none")]
1871    pub polymarket_url: Option<String>,
1872    #[serde(default)]
1873    pub outcome_label: Option<String>,
1874    #[serde(default)]
1875    pub image: Option<String>,
1876    #[serde(default)]
1877    pub category: Option<String>,
1878    /// Provider outcome index; negative sentinels describe void or unresolved states.
1879    #[serde(default)]
1880    pub winning_outcome: Option<i64>,
1881    #[serde(default)]
1882    pub resolved_at: Option<String>,
1883    /// A closed market may still have no terminal outcome.
1884    #[serde(default)]
1885    pub market_closed: Option<bool>,
1886    /// Stored daily price for this leg outcome token; not a live quote.
1887    #[serde(default)]
1888    pub pick_price_daily: Option<f64>,
1889    /// Observation time of the stored daily price.
1890    #[serde(default)]
1891    pub pick_price_as_of: Option<String>,
1892    /// Whole days since the stored daily bucket.
1893    #[serde(default)]
1894    pub pick_price_age_days: Option<i64>,
1895    /// Unmodified provider leg status when available.
1896    #[serde(default)]
1897    pub provider_leg_status: Option<String>,
1898}
1899
1900/// A value this release does not know is kept in `Other`, so a new value never fails a response.
1901#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1902#[non_exhaustive]
1903pub enum ComboLegMarketSource {
1904    /// `markets`
1905    #[serde(rename = "markets")]
1906    Markets,
1907    /// `provider`
1908    #[serde(rename = "provider")]
1909    Provider,
1910    /// A value this release does not know, kept as sent.
1911    #[serde(untagged)]
1912    Other(String),
1913}
1914
1915impl ComboLegMarketSource {
1916    /// The value as the API spells it.
1917    pub fn as_str(&self) -> &str {
1918        match self {
1919            Self::Markets => "markets",
1920            Self::Provider => "provider",
1921            Self::Other(value) => value,
1922        }
1923    }
1924}
1925
1926impl From<&str> for ComboLegMarketSource {
1927    fn from(value: &str) -> Self {
1928        match value {
1929            "markets" => Self::Markets,
1930            "provider" => Self::Provider,
1931            other => Self::Other(other.to_owned()),
1932        }
1933    }
1934}
1935
1936impl std::fmt::Display for ComboLegMarketSource {
1937    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1938        f.write_str(self.as_str())
1939    }
1940}
1941
1942impl AsRef<str> for ComboLegMarketSource {
1943    fn as_ref(&self) -> &str {
1944        self.as_str()
1945    }
1946}
1947
1948/// A value this release does not know is kept in `Other`, so a new value never fails a response.
1949#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1950#[non_exhaustive]
1951pub enum ComboLegState {
1952    /// `pending`
1953    #[serde(rename = "pending")]
1954    Pending,
1955    /// `won`
1956    #[serde(rename = "won")]
1957    Won,
1958    /// `lost`
1959    #[serde(rename = "lost")]
1960    Lost,
1961    /// `void`
1962    #[serde(rename = "void")]
1963    Void,
1964    /// `unknown`
1965    #[serde(rename = "unknown")]
1966    Unknown,
1967    /// A value this release does not know, kept as sent.
1968    #[serde(untagged)]
1969    Other(String),
1970}
1971
1972impl ComboLegState {
1973    /// The value as the API spells it.
1974    pub fn as_str(&self) -> &str {
1975        match self {
1976            Self::Pending => "pending",
1977            Self::Won => "won",
1978            Self::Lost => "lost",
1979            Self::Void => "void",
1980            Self::Unknown => "unknown",
1981            Self::Other(value) => value,
1982        }
1983    }
1984}
1985
1986impl From<&str> for ComboLegState {
1987    fn from(value: &str) -> Self {
1988        match value {
1989            "pending" => Self::Pending,
1990            "won" => Self::Won,
1991            "lost" => Self::Lost,
1992            "void" => Self::Void,
1993            "unknown" => Self::Unknown,
1994            other => Self::Other(other.to_owned()),
1995        }
1996    }
1997}
1998
1999impl std::fmt::Display for ComboLegState {
2000    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2001        f.write_str(self.as_str())
2002    }
2003}
2004
2005impl AsRef<str> for ComboLegState {
2006    fn as_ref(&self) -> &str {
2007        self.as_str()
2008    }
2009}
2010
2011#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2012#[non_exhaustive]
2013pub struct ComboLifecycleStats {
2014    pub splits: i64,
2015    pub merges: i64,
2016    pub redeems: i64,
2017    pub compresses: i64,
2018    /// Exact decimal string from the stored chain or SQL value; preserve precision until display.
2019    pub split_usdc: String,
2020    /// Exact decimal string from the stored chain or SQL value; preserve precision until display.
2021    pub merge_usdc: String,
2022    /// Exact decimal string from the stored chain or SQL value; preserve precision until display.
2023    pub redeemed_shares: String,
2024    /// Exact decimal string from the stored chain or SQL value; preserve precision until display.
2025    pub redeemed_usdc: String,
2026    /// Exact decimal string from the stored chain or SQL value; preserve precision until display.
2027    pub compressed_usdc: String,
2028    pub last_event_at: String,
2029}
2030
2031#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2032#[non_exhaustive]
2033pub struct ComboLiveCount {
2034    /// Traded combos whose YES conjunction remains pending.
2035    pub count: i64,
2036    /// Time the count was computed; check its age before using it.
2037    pub computed_at: String,
2038}
2039
2040#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2041#[non_exhaustive]
2042pub struct ComboResponse {
2043    pub object: String,
2044    pub data: ComboDetail,
2045    pub meta: ResponseMeta,
2046}
2047
2048/// A value this release does not know is kept in `Other`, so a new value never fails a response.
2049#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
2050#[non_exhaustive]
2051pub enum ComboStatus {
2052    /// `pending`
2053    #[serde(rename = "pending")]
2054    Pending,
2055    /// `won`
2056    #[serde(rename = "won")]
2057    Won,
2058    /// `lost`
2059    #[serde(rename = "lost")]
2060    Lost,
2061    /// `unknown`
2062    #[serde(rename = "unknown")]
2063    Unknown,
2064    /// A value this release does not know, kept as sent.
2065    #[serde(untagged)]
2066    Other(String),
2067}
2068
2069impl ComboStatus {
2070    /// The value as the API spells it.
2071    pub fn as_str(&self) -> &str {
2072        match self {
2073            Self::Pending => "pending",
2074            Self::Won => "won",
2075            Self::Lost => "lost",
2076            Self::Unknown => "unknown",
2077            Self::Other(value) => value,
2078        }
2079    }
2080}
2081
2082impl From<&str> for ComboStatus {
2083    fn from(value: &str) -> Self {
2084        match value {
2085            "pending" => Self::Pending,
2086            "won" => Self::Won,
2087            "lost" => Self::Lost,
2088            "unknown" => Self::Unknown,
2089            other => Self::Other(other.to_owned()),
2090        }
2091    }
2092}
2093
2094impl std::fmt::Display for ComboStatus {
2095    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2096        f.write_str(self.as_str())
2097    }
2098}
2099
2100impl AsRef<str> for ComboStatus {
2101    fn as_ref(&self) -> &str {
2102        self.as_str()
2103    }
2104}
2105
2106#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2107#[non_exhaustive]
2108pub struct ComboTotals {
2109    pub fills: i64,
2110    /// Exact decimal string from the stored chain or SQL value; preserve precision until display.
2111    pub volume_usdc: String,
2112    /// Exact decimal string from the stored chain or SQL value; preserve precision until display.
2113    pub largest_fill_usdc: String,
2114    pub first_fill_at: String,
2115    pub last_fill_at: String,
2116    /// Last taker execution normalized to YES; not a current quote.
2117    #[serde(default)]
2118    pub last_fill_price_yes: Option<String>,
2119    pub last_fill_outcome_index: i64,
2120    pub last_fill_action: Action,
2121}
2122
2123#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2124#[non_exhaustive]
2125pub struct ComboWindowStats {
2126    pub fills: i64,
2127    /// Exact decimal string from the stored chain or SQL value; preserve precision until display.
2128    pub volume_usdc: String,
2129    pub distinct_traders: i64,
2130    /// Exact decimal string from the stored chain or SQL value; preserve precision until display.
2131    pub largest_fill_usdc: String,
2132}
2133
2134/// Stored live combo count. Null means the first count is unavailable, never zero.
2135#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2136#[non_exhaustive]
2137pub struct CombosSummary {
2138    #[serde(default)]
2139    pub live: Option<ComboLiveCount>,
2140}
2141
2142#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2143#[non_exhaustive]
2144pub struct CombosSummaryResponse {
2145    pub object: String,
2146    pub data: CombosSummary,
2147    pub meta: ResponseMeta,
2148}
2149
2150/// A value this release does not know is kept in `Other`, so a new value never fails a response.
2151#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
2152#[non_exhaustive]
2153pub enum Competitors {
2154    /// `provider_ids`
2155    #[serde(rename = "provider_ids")]
2156    ProviderIds,
2157    /// `labels`
2158    #[serde(rename = "labels")]
2159    Labels,
2160    /// `unavailable`
2161    #[serde(rename = "unavailable")]
2162    Unavailable,
2163    /// A value this release does not know, kept as sent.
2164    #[serde(untagged)]
2165    Other(String),
2166}
2167
2168impl Competitors {
2169    /// The value as the API spells it.
2170    pub fn as_str(&self) -> &str {
2171        match self {
2172            Self::ProviderIds => "provider_ids",
2173            Self::Labels => "labels",
2174            Self::Unavailable => "unavailable",
2175            Self::Other(value) => value,
2176        }
2177    }
2178}
2179
2180impl From<&str> for Competitors {
2181    fn from(value: &str) -> Self {
2182        match value {
2183            "provider_ids" => Self::ProviderIds,
2184            "labels" => Self::Labels,
2185            "unavailable" => Self::Unavailable,
2186            other => Self::Other(other.to_owned()),
2187        }
2188    }
2189}
2190
2191impl std::fmt::Display for Competitors {
2192    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2193        f.write_str(self.as_str())
2194    }
2195}
2196
2197impl AsRef<str> for Competitors {
2198    fn as_ref(&self) -> &str {
2199        self.as_str()
2200    }
2201}
2202
2203/// A value this release does not know is kept in `Other`, so a new value never fails a response.
2204#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
2205#[non_exhaustive]
2206pub enum Consistency {
2207    /// `live`
2208    #[serde(rename = "live")]
2209    Live,
2210    /// `snapshot`
2211    #[serde(rename = "snapshot")]
2212    Snapshot,
2213    /// A value this release does not know, kept as sent.
2214    #[serde(untagged)]
2215    Other(String),
2216}
2217
2218impl Consistency {
2219    /// The value as the API spells it.
2220    pub fn as_str(&self) -> &str {
2221        match self {
2222            Self::Live => "live",
2223            Self::Snapshot => "snapshot",
2224            Self::Other(value) => value,
2225        }
2226    }
2227}
2228
2229impl From<&str> for Consistency {
2230    fn from(value: &str) -> Self {
2231        match value {
2232            "live" => Self::Live,
2233            "snapshot" => Self::Snapshot,
2234            other => Self::Other(other.to_owned()),
2235        }
2236    }
2237}
2238
2239impl std::fmt::Display for Consistency {
2240    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2241        f.write_str(self.as_str())
2242    }
2243}
2244
2245impl AsRef<str> for Consistency {
2246    fn as_ref(&self) -> &str {
2247        self.as_str()
2248    }
2249}
2250
2251/// A value this release does not know is kept in `Other`, so a new value never fails a response.
2252#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
2253#[non_exhaustive]
2254pub enum ContentKind {
2255    /// `learn`
2256    #[serde(rename = "learn")]
2257    Learn,
2258    /// `glossary`
2259    #[serde(rename = "glossary")]
2260    Glossary,
2261    /// `comparison`
2262    #[serde(rename = "comparison")]
2263    Comparison,
2264    /// `research`
2265    #[serde(rename = "research")]
2266    Research,
2267    /// `strategy`
2268    #[serde(rename = "strategy")]
2269    Strategy,
2270    /// A value this release does not know, kept as sent.
2271    #[serde(untagged)]
2272    Other(String),
2273}
2274
2275impl ContentKind {
2276    /// The value as the API spells it.
2277    pub fn as_str(&self) -> &str {
2278        match self {
2279            Self::Learn => "learn",
2280            Self::Glossary => "glossary",
2281            Self::Comparison => "comparison",
2282            Self::Research => "research",
2283            Self::Strategy => "strategy",
2284            Self::Other(value) => value,
2285        }
2286    }
2287}
2288
2289impl From<&str> for ContentKind {
2290    fn from(value: &str) -> Self {
2291        match value {
2292            "learn" => Self::Learn,
2293            "glossary" => Self::Glossary,
2294            "comparison" => Self::Comparison,
2295            "research" => Self::Research,
2296            "strategy" => Self::Strategy,
2297            other => Self::Other(other.to_owned()),
2298        }
2299    }
2300}
2301
2302impl std::fmt::Display for ContentKind {
2303    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2304        f.write_str(self.as_str())
2305    }
2306}
2307
2308impl AsRef<str> for ContentKind {
2309    fn as_ref(&self) -> &str {
2310        self.as_str()
2311    }
2312}
2313
2314#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2315#[non_exhaustive]
2316pub struct ContentSearchResult {
2317    /// Backend-owned stable editorial content identifier.
2318    pub content_id: String,
2319    /// Editorial content kind.
2320    pub kind: ContentKind,
2321    /// Backend-owned content slug.
2322    pub slug: String,
2323    /// Editorial title.
2324    pub title: String,
2325    /// Search-result excerpt.
2326    pub excerpt: String,
2327    /// Canonical first-party content URL.
2328    pub url: String,
2329}
2330
2331/// A value this release does not know is kept in `Other`, so a new value never fails a response.
2332#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
2333#[non_exhaustive]
2334pub enum ContentType {
2335    /// `application/json`
2336    #[serde(rename = "application/json")]
2337    ApplicationJson,
2338    /// `application/x-ndjson`
2339    #[serde(rename = "application/x-ndjson")]
2340    ApplicationXNdjson,
2341    /// `text/csv`
2342    #[serde(rename = "text/csv")]
2343    TextCsv,
2344    /// A value this release does not know, kept as sent.
2345    #[serde(untagged)]
2346    Other(String),
2347}
2348
2349impl ContentType {
2350    /// The value as the API spells it.
2351    pub fn as_str(&self) -> &str {
2352        match self {
2353            Self::ApplicationJson => "application/json",
2354            Self::ApplicationXNdjson => "application/x-ndjson",
2355            Self::TextCsv => "text/csv",
2356            Self::Other(value) => value,
2357        }
2358    }
2359}
2360
2361impl From<&str> for ContentType {
2362    fn from(value: &str) -> Self {
2363        match value {
2364            "application/json" => Self::ApplicationJson,
2365            "application/x-ndjson" => Self::ApplicationXNdjson,
2366            "text/csv" => Self::TextCsv,
2367            other => Self::Other(other.to_owned()),
2368        }
2369    }
2370}
2371
2372impl std::fmt::Display for ContentType {
2373    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2374        f.write_str(self.as_str())
2375    }
2376}
2377
2378impl AsRef<str> for ContentType {
2379    fn as_ref(&self) -> &str {
2380        self.as_str()
2381    }
2382}
2383
2384#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2385#[non_exhaustive]
2386pub struct CounterpartyAnalysis {
2387    pub status: CounterpartyAnalysisStatus,
2388    #[serde(default, skip_serializing_if = "Option::is_none")]
2389    pub unavailable_reason: Option<String>,
2390    /// Deterministic immutable membership snapshot for this detail response.
2391    #[serde(default, skip_serializing_if = "Option::is_none")]
2392    pub snapshot_id: Option<String>,
2393    /// Stable digest binding page cursors to one snapshot and execution set.
2394    #[serde(default, skip_serializing_if = "Option::is_none")]
2395    pub analysis_id: Option<String>,
2396    pub execution_count: i64,
2397    pub available_execution_count: i64,
2398    pub unavailable_execution_count: i64,
2399    pub executions: Vec<CounterpartyExecution>,
2400    /// Stable cursor after the last execution included in the bounded inline page.
2401    #[serde(default, skip_serializing_if = "Option::is_none")]
2402    pub executions_next_cursor: Option<String>,
2403}
2404
2405/// A value this release does not know is kept in `Other`, so a new value never fails a response.
2406#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
2407#[non_exhaustive]
2408pub enum CounterpartyAnalysisStatus {
2409    /// `available`
2410    #[serde(rename = "available")]
2411    Available,
2412    /// `partial`
2413    #[serde(rename = "partial")]
2414    Partial,
2415    /// `unavailable`
2416    #[serde(rename = "unavailable")]
2417    Unavailable,
2418    /// A value this release does not know, kept as sent.
2419    #[serde(untagged)]
2420    Other(String),
2421}
2422
2423impl CounterpartyAnalysisStatus {
2424    /// The value as the API spells it.
2425    pub fn as_str(&self) -> &str {
2426        match self {
2427            Self::Available => "available",
2428            Self::Partial => "partial",
2429            Self::Unavailable => "unavailable",
2430            Self::Other(value) => value,
2431        }
2432    }
2433}
2434
2435impl From<&str> for CounterpartyAnalysisStatus {
2436    fn from(value: &str) -> Self {
2437        match value {
2438            "available" => Self::Available,
2439            "partial" => Self::Partial,
2440            "unavailable" => Self::Unavailable,
2441            other => Self::Other(other.to_owned()),
2442        }
2443    }
2444}
2445
2446impl std::fmt::Display for CounterpartyAnalysisStatus {
2447    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2448        f.write_str(self.as_str())
2449    }
2450}
2451
2452impl AsRef<str> for CounterpartyAnalysisStatus {
2453    fn as_ref(&self) -> &str {
2454        self.as_str()
2455    }
2456}
2457
2458#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2459#[non_exhaustive]
2460pub struct CounterpartyExecution {
2461    pub execution_id: String,
2462    /// 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.
2463    pub exchange_family: ExchangeFamily,
2464    pub transaction_hash: String,
2465    pub orders_matched_log_index: i64,
2466    pub taker: CounterpartyParticipant,
2467    pub makers: Vec<CounterpartyParticipant>,
2468    /// Stable cursor after the last maker included in the bounded inline page.
2469    #[serde(default, skip_serializing_if = "Option::is_none")]
2470    pub makers_next_cursor: Option<String>,
2471}
2472
2473#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2474#[non_exhaustive]
2475pub struct CounterpartyMakerPage {
2476    pub analysis_id: String,
2477    pub snapshot_id: String,
2478    pub execution_id: String,
2479    pub items: Vec<CounterpartyParticipant>,
2480    /// Cursor bound to the analysis, execution, last full-denominator share total, and wallet.
2481    #[serde(default, skip_serializing_if = "Option::is_none")]
2482    pub next_cursor: Option<String>,
2483}
2484
2485#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2486#[non_exhaustive]
2487pub struct CounterpartyMatchBreakdown {
2488    pub match_type: MatchType,
2489    pub maker_fill_count: i64,
2490    /// Exact decimal shares.
2491    pub filled_shares: String,
2492}
2493
2494#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2495#[non_exhaustive]
2496pub struct CounterpartyParticipant {
2497    pub counterparty_key: String,
2498    /// Lowercase Polygon wallet from the exact OrderFilled log.
2499    pub execution_wallet: String,
2500    pub identity_status: IdentityStatus,
2501    #[serde(default, skip_serializing_if = "Option::is_none")]
2502    pub resolved_user_id: Option<String>,
2503    #[serde(default, skip_serializing_if = "Option::is_none")]
2504    pub wallet_family: Option<String>,
2505    #[serde(default, skip_serializing_if = "Option::is_none")]
2506    pub resolution_block: Option<i64>,
2507    #[serde(default, skip_serializing_if = "Option::is_none")]
2508    pub resolution_source: Option<String>,
2509    #[serde(default, skip_serializing_if = "Option::is_none")]
2510    pub display_name: Option<String>,
2511    #[serde(default, skip_serializing_if = "Option::is_none")]
2512    pub grade: Option<String>,
2513    /// 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.
2514    #[serde(default, skip_serializing_if = "Option::is_none")]
2515    pub last_traded_at: Option<String>,
2516    /// 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/`.
2517    #[serde(default, skip_serializing_if = "Option::is_none")]
2518    pub profile_segment: Option<String>,
2519    pub maker_fill_count: i64,
2520    /// Exact decimal shares.
2521    pub filled_shares: String,
2522    /// Exact decimal USDC amount.
2523    pub filled_usdc: String,
2524    /// Participant share of the exact execution, from 0 through 100.
2525    pub share_pct: String,
2526    pub match_breakdown: Vec<CounterpartyMatchBreakdown>,
2527}
2528
2529/// A value this release does not know is kept in `Other`, so a new value never fails a response.
2530#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
2531#[non_exhaustive]
2532pub enum Coverage {
2533    /// `full_envelope_and_trades`
2534    #[serde(rename = "full_envelope_and_trades")]
2535    FullEnvelopeAndTrades,
2536    /// `trades_only`
2537    #[serde(rename = "trades_only")]
2538    TradesOnly,
2539    /// A value this release does not know, kept as sent.
2540    #[serde(untagged)]
2541    Other(String),
2542}
2543
2544impl Coverage {
2545    /// The value as the API spells it.
2546    pub fn as_str(&self) -> &str {
2547        match self {
2548            Self::FullEnvelopeAndTrades => "full_envelope_and_trades",
2549            Self::TradesOnly => "trades_only",
2550            Self::Other(value) => value,
2551        }
2552    }
2553}
2554
2555impl From<&str> for Coverage {
2556    fn from(value: &str) -> Self {
2557        match value {
2558            "full_envelope_and_trades" => Self::FullEnvelopeAndTrades,
2559            "trades_only" => Self::TradesOnly,
2560            other => Self::Other(other.to_owned()),
2561        }
2562    }
2563}
2564
2565impl std::fmt::Display for Coverage {
2566    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2567        f.write_str(self.as_str())
2568    }
2569}
2570
2571impl AsRef<str> for Coverage {
2572    fn as_ref(&self) -> &str {
2573        self.as_str()
2574    }
2575}
2576
2577#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2578pub struct CreateMcpJsonRpcResponseBody {
2579    /// JSON-RPC protocol version; this server accepts 2.0.
2580    pub jsonrpc: String,
2581    /// 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.
2582    #[serde(default, skip_serializing_if = "Option::is_none")]
2583    pub id: Option<serde_json::Value>,
2584    /// MCP method to invoke.
2585    pub method: McpMethod,
2586    /// Method-specific MCP parameters.
2587    #[serde(default, skip_serializing_if = "Option::is_none")]
2588    pub params: Option<serde_json::Map<String, serde_json::Value>>,
2589}
2590
2591#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2592#[non_exhaustive]
2593pub struct CreateMcpJsonRpcResponseResponse {
2594    pub jsonrpc: String,
2595    #[serde(default)]
2596    pub id: Option<serde_json::Value>,
2597    #[serde(default, skip_serializing_if = "Option::is_none")]
2598    pub result: Option<serde_json::Map<String, serde_json::Value>>,
2599    #[serde(default, skip_serializing_if = "Option::is_none")]
2600    pub error: Option<CreateMcpJsonRpcResponseResponseError>,
2601}
2602
2603#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2604#[non_exhaustive]
2605pub struct CreateMcpJsonRpcResponseResponseError {
2606    pub code: i64,
2607    pub message: String,
2608    /// Optional JSON-serializable error data.
2609    #[serde(default, skip_serializing_if = "Option::is_none")]
2610    pub data: Option<serde_json::Value>,
2611}
2612
2613#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2614pub struct CreateWebhookRequest {
2615    pub name: String,
2616    /// 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.
2617    pub url: String,
2618    pub event_types: Vec<WebhookEventType>,
2619    #[serde(default, skip_serializing_if = "Option::is_none")]
2620    pub trade_filters: Option<LargeTradeSubscriptionFilters>,
2621}
2622
2623#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2624#[non_exhaustive]
2625pub struct CreateWebhookResponse {
2626    pub object: String,
2627    pub data: WebhookEndpoint,
2628    pub meta: ResponseMeta,
2629}
2630
2631#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2632pub struct CreateWebhookVerificationAttemptRequest {
2633    /// The original one-time token returned by webhook creation or a URL change. Sent only in the request body and signed receiver challenge.
2634    pub verification_token: String,
2635}
2636
2637#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2638#[non_exhaustive]
2639pub struct CreateWebhookVerificationAttemptResponse {
2640    pub object: String,
2641    pub data: WebhookVerificationAttempt,
2642    pub meta: ResponseMeta,
2643}
2644
2645/// A value this release does not know is kept in `Other`, so a new value never fails a response.
2646#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
2647#[non_exhaustive]
2648pub enum CredentialKind {
2649    /// `api_key`
2650    #[serde(rename = "api_key")]
2651    ApiKey,
2652    /// `oauth_grant`
2653    #[serde(rename = "oauth_grant")]
2654    OauthGrant,
2655    /// `integration_key`
2656    #[serde(rename = "integration_key")]
2657    IntegrationKey,
2658    /// A value this release does not know, kept as sent.
2659    #[serde(untagged)]
2660    Other(String),
2661}
2662
2663impl CredentialKind {
2664    /// The value as the API spells it.
2665    pub fn as_str(&self) -> &str {
2666        match self {
2667            Self::ApiKey => "api_key",
2668            Self::OauthGrant => "oauth_grant",
2669            Self::IntegrationKey => "integration_key",
2670            Self::Other(value) => value,
2671        }
2672    }
2673}
2674
2675impl From<&str> for CredentialKind {
2676    fn from(value: &str) -> Self {
2677        match value {
2678            "api_key" => Self::ApiKey,
2679            "oauth_grant" => Self::OauthGrant,
2680            "integration_key" => Self::IntegrationKey,
2681            other => Self::Other(other.to_owned()),
2682        }
2683    }
2684}
2685
2686impl std::fmt::Display for CredentialKind {
2687    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2688        f.write_str(self.as_str())
2689    }
2690}
2691
2692impl AsRef<str> for CredentialKind {
2693    fn as_ref(&self) -> &str {
2694        self.as_str()
2695    }
2696}
2697
2698/// A value this release does not know is kept in `Other`, so a new value never fails a response.
2699#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
2700#[non_exhaustive]
2701pub enum DailyPnlSeriesStatus {
2702    /// `ready`
2703    #[serde(rename = "ready")]
2704    Ready,
2705    /// `pending`
2706    #[serde(rename = "pending")]
2707    Pending,
2708    /// A value this release does not know, kept as sent.
2709    #[serde(untagged)]
2710    Other(String),
2711}
2712
2713impl DailyPnlSeriesStatus {
2714    /// The value as the API spells it.
2715    pub fn as_str(&self) -> &str {
2716        match self {
2717            Self::Ready => "ready",
2718            Self::Pending => "pending",
2719            Self::Other(value) => value,
2720        }
2721    }
2722}
2723
2724impl From<&str> for DailyPnlSeriesStatus {
2725    fn from(value: &str) -> Self {
2726        match value {
2727            "ready" => Self::Ready,
2728            "pending" => Self::Pending,
2729            other => Self::Other(other.to_owned()),
2730        }
2731    }
2732}
2733
2734impl std::fmt::Display for DailyPnlSeriesStatus {
2735    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2736        f.write_str(self.as_str())
2737    }
2738}
2739
2740impl AsRef<str> for DailyPnlSeriesStatus {
2741    fn as_ref(&self) -> &str {
2742        self.as_str()
2743    }
2744}
2745
2746/// 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.
2747#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2748#[non_exhaustive]
2749pub struct DataQuality {
2750    /// 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.
2751    pub status: DataQualityGroupStatus,
2752    /// 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.
2753    #[serde(default, skip_serializing_if = "Option::is_none")]
2754    pub as_of: Option<String>,
2755    /// One entry per field group. Entries may be added in later releases, so match on group rather than on position or length.
2756    pub field_groups: Vec<DataQualityGroup>,
2757}
2758
2759/// One group of response fields that share a writer and therefore share a clock.
2760#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2761#[non_exhaustive]
2762pub struct DataQualityGroup {
2763    /// Stable snake_case group name. Names are additive across releases, so match on the ones you know and ignore the rest.
2764    pub group: String,
2765    /// The table and column that write this group, named so the verdict can be audited (for example trader_rankings.computed_at).
2766    pub owner: String,
2767    /// 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.
2768    pub status: DataQualityGroupStatus,
2769    /// 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.
2770    #[serde(default, skip_serializing_if = "Option::is_none")]
2771    pub as_of: Option<String>,
2772    /// Why the status is not fresh. Omitted when it is.
2773    #[serde(default, skip_serializing_if = "Option::is_none")]
2774    pub reason: Option<String>,
2775    /// 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.
2776    #[serde(default, skip_serializing_if = "Option::is_none")]
2777    pub max_age_s: Option<i64>,
2778}
2779
2780/// A value this release does not know is kept in `Other`, so a new value never fails a response.
2781#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
2782#[non_exhaustive]
2783pub enum DataQualityGroupStatus {
2784    /// `fresh`
2785    #[serde(rename = "fresh")]
2786    Fresh,
2787    /// `stale`
2788    #[serde(rename = "stale")]
2789    Stale,
2790    /// `partial`
2791    #[serde(rename = "partial")]
2792    Partial,
2793    /// `unknown`
2794    #[serde(rename = "unknown")]
2795    Unknown,
2796    /// `untracked`
2797    #[serde(rename = "untracked")]
2798    Untracked,
2799    /// `unavailable`
2800    #[serde(rename = "unavailable")]
2801    Unavailable,
2802    /// A value this release does not know, kept as sent.
2803    #[serde(untagged)]
2804    Other(String),
2805}
2806
2807impl DataQualityGroupStatus {
2808    /// The value as the API spells it.
2809    pub fn as_str(&self) -> &str {
2810        match self {
2811            Self::Fresh => "fresh",
2812            Self::Stale => "stale",
2813            Self::Partial => "partial",
2814            Self::Unknown => "unknown",
2815            Self::Untracked => "untracked",
2816            Self::Unavailable => "unavailable",
2817            Self::Other(value) => value,
2818        }
2819    }
2820}
2821
2822impl From<&str> for DataQualityGroupStatus {
2823    fn from(value: &str) -> Self {
2824        match value {
2825            "fresh" => Self::Fresh,
2826            "stale" => Self::Stale,
2827            "partial" => Self::Partial,
2828            "unknown" => Self::Unknown,
2829            "untracked" => Self::Untracked,
2830            "unavailable" => Self::Unavailable,
2831            other => Self::Other(other.to_owned()),
2832        }
2833    }
2834}
2835
2836impl std::fmt::Display for DataQualityGroupStatus {
2837    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2838        f.write_str(self.as_str())
2839    }
2840}
2841
2842impl AsRef<str> for DataQualityGroupStatus {
2843    fn as_ref(&self) -> &str {
2844        self.as_str()
2845    }
2846}
2847
2848#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2849#[non_exhaustive]
2850pub struct DeleteWebhookResponse {
2851    pub object: String,
2852    pub data: WebhookEndpoint,
2853    pub meta: ResponseMeta,
2854}
2855
2856/// A value this release does not know is kept in `Other`, so a new value never fails a response.
2857#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
2858#[non_exhaustive]
2859pub enum Dir {
2860    /// `asc`
2861    #[serde(rename = "asc")]
2862    Asc,
2863    /// `desc`
2864    #[serde(rename = "desc")]
2865    Desc,
2866    /// A value this release does not know, kept as sent.
2867    #[serde(untagged)]
2868    Other(String),
2869}
2870
2871impl Dir {
2872    /// The value as the API spells it.
2873    pub fn as_str(&self) -> &str {
2874        match self {
2875            Self::Asc => "asc",
2876            Self::Desc => "desc",
2877            Self::Other(value) => value,
2878        }
2879    }
2880}
2881
2882impl From<&str> for Dir {
2883    fn from(value: &str) -> Self {
2884        match value {
2885            "asc" => Self::Asc,
2886            "desc" => Self::Desc,
2887            other => Self::Other(other.to_owned()),
2888        }
2889    }
2890}
2891
2892impl std::fmt::Display for Dir {
2893    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2894        f.write_str(self.as_str())
2895    }
2896}
2897
2898impl AsRef<str> for Dir {
2899    fn as_ref(&self) -> &str {
2900        self.as_str()
2901    }
2902}
2903
2904/// A value this release does not know is kept in `Other`, so a new value never fails a response.
2905#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
2906#[non_exhaustive]
2907pub enum Direction {
2908    /// `YES`
2909    #[serde(rename = "YES")]
2910    Yes,
2911    /// `NO`
2912    #[serde(rename = "NO")]
2913    No,
2914    /// A value this release does not know, kept as sent.
2915    #[serde(untagged)]
2916    Other(String),
2917}
2918
2919impl Direction {
2920    /// The value as the API spells it.
2921    pub fn as_str(&self) -> &str {
2922        match self {
2923            Self::Yes => "YES",
2924            Self::No => "NO",
2925            Self::Other(value) => value,
2926        }
2927    }
2928}
2929
2930impl From<&str> for Direction {
2931    fn from(value: &str) -> Self {
2932        match value {
2933            "YES" => Self::Yes,
2934            "NO" => Self::No,
2935            other => Self::Other(other.to_owned()),
2936        }
2937    }
2938}
2939
2940impl std::fmt::Display for Direction {
2941    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2942        f.write_str(self.as_str())
2943    }
2944}
2945
2946impl AsRef<str> for Direction {
2947    fn as_ref(&self) -> &str {
2948        self.as_str()
2949    }
2950}
2951
2952/// A value this release does not know is kept in `Other`, so a new value never fails a response.
2953#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
2954#[non_exhaustive]
2955pub enum DirectionalSource {
2956    /// `live`
2957    #[serde(rename = "live")]
2958    Live,
2959    /// `degraded`
2960    #[serde(rename = "degraded")]
2961    Degraded,
2962    /// A value this release does not know, kept as sent.
2963    #[serde(untagged)]
2964    Other(String),
2965}
2966
2967impl DirectionalSource {
2968    /// The value as the API spells it.
2969    pub fn as_str(&self) -> &str {
2970        match self {
2971            Self::Live => "live",
2972            Self::Degraded => "degraded",
2973            Self::Other(value) => value,
2974        }
2975    }
2976}
2977
2978impl From<&str> for DirectionalSource {
2979    fn from(value: &str) -> Self {
2980        match value {
2981            "live" => Self::Live,
2982            "degraded" => Self::Degraded,
2983            other => Self::Other(other.to_owned()),
2984        }
2985    }
2986}
2987
2988impl std::fmt::Display for DirectionalSource {
2989    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2990        f.write_str(self.as_str())
2991    }
2992}
2993
2994impl AsRef<str> for DirectionalSource {
2995    fn as_ref(&self) -> &str {
2996        self.as_str()
2997    }
2998}
2999
3000/// A value this release does not know is kept in `Other`, so a new value never fails a response.
3001#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
3002#[non_exhaustive]
3003pub enum DirectionalStatus {
3004    /// `available`
3005    #[serde(rename = "available")]
3006    Available,
3007    /// `unknown_ungrouped`
3008    #[serde(rename = "unknown_ungrouped")]
3009    UnknownUngrouped,
3010    /// `unknown_stale`
3011    #[serde(rename = "unknown_stale")]
3012    UnknownStale,
3013    /// `unavailable`
3014    #[serde(rename = "unavailable")]
3015    Unavailable,
3016    /// A value this release does not know, kept as sent.
3017    #[serde(untagged)]
3018    Other(String),
3019}
3020
3021impl DirectionalStatus {
3022    /// The value as the API spells it.
3023    pub fn as_str(&self) -> &str {
3024        match self {
3025            Self::Available => "available",
3026            Self::UnknownUngrouped => "unknown_ungrouped",
3027            Self::UnknownStale => "unknown_stale",
3028            Self::Unavailable => "unavailable",
3029            Self::Other(value) => value,
3030        }
3031    }
3032}
3033
3034impl From<&str> for DirectionalStatus {
3035    fn from(value: &str) -> Self {
3036        match value {
3037            "available" => Self::Available,
3038            "unknown_ungrouped" => Self::UnknownUngrouped,
3039            "unknown_stale" => Self::UnknownStale,
3040            "unavailable" => Self::Unavailable,
3041            other => Self::Other(other.to_owned()),
3042        }
3043    }
3044}
3045
3046impl std::fmt::Display for DirectionalStatus {
3047    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3048        f.write_str(self.as_str())
3049    }
3050}
3051
3052impl AsRef<str> for DirectionalStatus {
3053    fn as_ref(&self) -> &str {
3054        self.as_str()
3055    }
3056}
3057
3058/// A value this release does not know is kept in `Other`, so a new value never fails a response.
3059#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
3060#[non_exhaustive]
3061pub enum Draw {
3062    /// `main`
3063    #[serde(rename = "main")]
3064    Main,
3065    /// `qualification`
3066    #[serde(rename = "qualification")]
3067    Qualification,
3068    /// A value this release does not know, kept as sent.
3069    #[serde(untagged)]
3070    Other(String),
3071}
3072
3073impl Draw {
3074    /// The value as the API spells it.
3075    pub fn as_str(&self) -> &str {
3076        match self {
3077            Self::Main => "main",
3078            Self::Qualification => "qualification",
3079            Self::Other(value) => value,
3080        }
3081    }
3082}
3083
3084impl From<&str> for Draw {
3085    fn from(value: &str) -> Self {
3086        match value {
3087            "main" => Self::Main,
3088            "qualification" => Self::Qualification,
3089            other => Self::Other(other.to_owned()),
3090        }
3091    }
3092}
3093
3094impl std::fmt::Display for Draw {
3095    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3096        f.write_str(self.as_str())
3097    }
3098}
3099
3100impl AsRef<str> for Draw {
3101    fn as_ref(&self) -> &str {
3102        self.as_str()
3103    }
3104}
3105
3106/// A value this release does not know is kept in `Other`, so a new value never fails a response.
3107#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
3108#[non_exhaustive]
3109pub enum EdgeHold {
3110    /// `category_loss`
3111    #[serde(rename = "category_loss")]
3112    CategoryLoss,
3113    /// `record_incomplete`
3114    #[serde(rename = "record_incomplete")]
3115    RecordIncomplete,
3116    /// A value this release does not know, kept as sent.
3117    #[serde(untagged)]
3118    Other(String),
3119}
3120
3121impl EdgeHold {
3122    /// The value as the API spells it.
3123    pub fn as_str(&self) -> &str {
3124        match self {
3125            Self::CategoryLoss => "category_loss",
3126            Self::RecordIncomplete => "record_incomplete",
3127            Self::Other(value) => value,
3128        }
3129    }
3130}
3131
3132impl From<&str> for EdgeHold {
3133    fn from(value: &str) -> Self {
3134        match value {
3135            "category_loss" => Self::CategoryLoss,
3136            "record_incomplete" => Self::RecordIncomplete,
3137            other => Self::Other(other.to_owned()),
3138        }
3139    }
3140}
3141
3142impl std::fmt::Display for EdgeHold {
3143    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3144        f.write_str(self.as_str())
3145    }
3146}
3147
3148impl AsRef<str> for EdgeHold {
3149    fn as_ref(&self) -> &str {
3150        self.as_str()
3151    }
3152}
3153
3154/// 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.
3155#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3156#[non_exhaustive]
3157pub struct EdgeHunterBoard {
3158    /// When the ranked snapshot was computed. Date current quotes with their own ts values.
3159    pub as_of: String,
3160    pub horizon_hours: i64,
3161    /// Requested holder-presence grade floor, S/A/B. A holder at that grade or better admits the row; other holders remain visible.
3162    pub min_grade: MarketHolderGrade,
3163    /// live uses the current graded holder pile; db_only is a weaker stored-data fallback.
3164    pub ranking_source: RankingSource,
3165    /// degraded means directional enrichment was unavailable.
3166    pub directional_source: DirectionalSource,
3167    #[serde(default)]
3168    pub cached_age_seconds: Option<i64>,
3169    pub viewer: String,
3170    /// Always null: Edge Hunter has no free signal slot.
3171    #[serde(default)]
3172    pub free_rank: Option<i64>,
3173    /// Ranked rows after normalized selections and grade filtering, before the view-specific limit cap.
3174    pub total: i64,
3175    pub rows: Vec<EdgeHunterRow>,
3176}
3177
3178#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3179#[non_exhaustive]
3180pub struct EdgeHunterBoardResponse {
3181    pub object: String,
3182    pub data: EdgeHunterBoard,
3183    pub meta: ResponseMeta,
3184    /// Normalized axes requested with a selector or category; omitted on an unselected default read.
3185    #[serde(default, skip_serializing_if = "Option::is_none")]
3186    pub selection: Option<EdgeHunterSelection>,
3187}
3188
3189/// Category evidence over the full uncapped piled-side S/A/B holder allocation. It never changes signal membership, ordering, routing, or sizing.
3190#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3191#[non_exhaustive]
3192pub struct EdgeHunterCategorySkill {
3193    pub status: Status,
3194    pub model_version: String,
3195    #[serde(default)]
3196    pub taxonomy_version: Option<String>,
3197    pub platform: String,
3198    pub scope: String,
3199    pub source_coverage: SourceCoverage,
3200    pub observation_started_at: String,
3201    pub as_of: String,
3202    #[serde(default)]
3203    pub canonical_category: Option<String>,
3204    pub eligible_holders: i64,
3205    pub covered_holders: i64,
3206    #[serde(default)]
3207    pub backed_sharp_usd: Option<f64>,
3208    #[serde(default)]
3209    pub covered_backed_usd: Option<f64>,
3210    #[serde(default)]
3211    pub coverage_pct: Option<f64>,
3212    #[serde(default)]
3213    pub weighted_edge_mean: Option<f64>,
3214    #[serde(default)]
3215    pub weighted_holder_lower_mean: Option<f64>,
3216    #[serde(default)]
3217    pub specialist_backed_usd: Option<f64>,
3218    #[serde(default)]
3219    pub specialist_backed_usd_pct: Option<f64>,
3220    #[serde(default)]
3221    pub largest_holder_backed_usd_pct: Option<f64>,
3222    #[serde(default)]
3223    pub minimum_holder_event_count: Option<i64>,
3224}
3225
3226/// Per-sport accountable funnel for the full observation snapshot, returned on every page.
3227#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3228#[non_exhaustive]
3229pub struct EdgeHunterFunnelReport {
3230    pub sports: Vec<EdgeHunterSportFunnelReport>,
3231}
3232
3233/// 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.
3234#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3235#[non_exhaustive]
3236pub struct EdgeHunterMarketContext {
3237    /// Normalized machine/provider league identity. Known wire/tag aliases normalize; other provider identities match exact lowercase keys.
3238    #[serde(default)]
3239    pub league: Option<String>,
3240    /// Exact provider series slug, usable in series_slugs selection.
3241    #[serde(default)]
3242    pub series_slug: Option<String>,
3243    /// Exact provider sports_market_type, usable in market_types selection.
3244    #[serde(default)]
3245    pub market_type: Option<String>,
3246    /// Exact local canonical metadata writer market_canonical.updated_at. This is not a provider observation clock; null means unavailable.
3247    #[serde(default)]
3248    pub metadata_updated_at: Option<String>,
3249}
3250
3251/// 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.
3252#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3253#[non_exhaustive]
3254pub struct EdgeHunterObservation {
3255    /// 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.
3256    #[serde(default)]
3257    pub side: Option<String>,
3258    /// Recorded side backing score; higher values indicate stronger backing.
3259    pub backing_score: f64,
3260    /// Signed share of graded money on the side, in [-1, 1]. Canonical spelling of smart_score (#16309, #16310), same value.
3261    pub side_share: f64,
3262    /// Raw Polymarket condition id.
3263    pub condition_id: String,
3264    /// Provider-backed Polymarket CLOB token id for the piled outcome. Rows without a verified token terminate before emission.
3265    pub token_id: String,
3266    /// Canonical sport bucket.
3267    pub category: Category,
3268    /// Raw provider category as stored.
3269    #[serde(default)]
3270    pub raw_category: Option<String>,
3271    /// Provider-backed market title.
3272    pub title: String,
3273    #[serde(default)]
3274    pub event_slug: Option<String>,
3275    /// Provider event id when available.
3276    #[serde(default)]
3277    pub event_id: Option<String>,
3278    /// Provider parent-event id used as the first event-cap identity when available.
3279    #[serde(default)]
3280    pub parent_event_id: Option<String>,
3281    /// Provider-backed kickoff time in UTC.
3282    pub game_start_time: String,
3283    /// UTC instant when this row finished provider/holder evaluation.
3284    pub observed_at: String,
3285    /// 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.
3286    pub cohort: Cohort,
3287    /// 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.
3288    pub admitted_by: AdmittedBy,
3289    /// Always true. This row must not be routed to an order executor.
3290    pub observation_only: bool,
3291    /// 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.
3292    #[serde(default)]
3293    pub piled_side: Option<String>,
3294    /// 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.
3295    pub piled_outcome_index: i64,
3296    /// Aggregate piled-side market midpoint recorded at observed_at. This is an observation price mark, not a wallet entry cost.
3297    pub backed_price: f64,
3298    /// Piled-side graded-holder dollar concentration.
3299    pub sharp_pct: f64,
3300    /// Raw graded-holder USD on the piled outcome.
3301    pub backed_sharp_usd: f64,
3302    pub s_count: i64,
3303    pub a_count: i64,
3304    pub b_count: i64,
3305    /// Piled-side S/A/B holder count.
3306    pub graded_holders: i64,
3307    pub top_grade: MarketHolderGrade,
3308    /// Canonical signed holder-pile score. Deprecated (#16310): `side_share` is the canonical spelling and carries the same value; this key stays on the wire.
3309    pub smart_score: f64,
3310    /// Cumulative provider taker volume in shares, not cash or dollars.
3311    pub volume: f64,
3312    /// Recorded conviction score; higher values indicate stronger conviction.
3313    pub conviction_score: f64,
3314    /// Whether the provider holder page came from the shared cache or a live provider read.
3315    pub provider_read_source: ProviderReadSource,
3316    /// 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.
3317    pub holder_scan_complete: bool,
3318    /// 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.
3319    #[serde(default)]
3320    pub holder_snapshot_at: Option<String>,
3321    /// 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.
3322    pub directional_status: DirectionalStatus,
3323    #[serde(default)]
3324    pub one_way_holder_count: Option<i64>,
3325    #[serde(default)]
3326    pub hedged_holder_count: Option<i64>,
3327    #[serde(default)]
3328    pub one_way_graded_usd: Option<f64>,
3329    #[serde(default)]
3330    pub directional_confidence: Option<f64>,
3331    /// Recorded side ordering score; higher values sort first.
3332    pub directional_rank_score: f64,
3333    /// 1-based rank within this observation cohort and snapshot.
3334    pub rank: i64,
3335    /// Required nullable frozen metadata context. Null only during the legacy-generation transition; selected reads require sidecar readiness and fail closed with 503 instead.
3336    #[serde(default)]
3337    pub market_context: Option<EdgeHunterMarketContext>,
3338}
3339
3340/// 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.
3341#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3342#[non_exhaustive]
3343pub struct EdgeHunterObservationCoverage {
3344    /// Sum of canonical source-generation funnel input across all sports, before category, cohort or selector projection.
3345    pub input_markets: i64,
3346    /// 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.
3347    pub capacity_limited_markets: i64,
3348    /// 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.
3349    pub emitted_observations: i64,
3350    /// 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.
3351    pub incomplete_holder_markets: i64,
3352    /// Observations matching the requested cohort, category, selectors and applicable pinned projection cutoff before pagination.
3353    pub selected_observations: i64,
3354    /// Observation rows on this page; equals data.length.
3355    pub returned_observations: i64,
3356}
3357
3358/// 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.
3359#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3360#[non_exhaustive]
3361pub struct EdgeHunterObservationDegradationReason {
3362    /// 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.
3363    pub reason: EdgeHunterObservationDegradationReasonReason,
3364    /// Canonical sport for the recorded cause; null only for generation-wide evidence without a sport attribution.
3365    #[serde(default)]
3366    pub sport: Option<String>,
3367}
3368
3369/// A value this release does not know is kept in `Other`, so a new value never fails a response.
3370#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
3371#[non_exhaustive]
3372pub enum EdgeHunterObservationDegradationReasonReason {
3373    /// `holder_scan_incomplete`
3374    #[serde(rename = "holder_scan_incomplete")]
3375    HolderScanIncomplete,
3376    /// `live_source_stale`
3377    #[serde(rename = "live_source_stale")]
3378    LiveSourceStale,
3379    /// `directional_unavailable`
3380    #[serde(rename = "directional_unavailable")]
3381    DirectionalUnavailable,
3382    /// `funnel_unreconciled`
3383    #[serde(rename = "funnel_unreconciled")]
3384    FunnelUnreconciled,
3385    /// `board_live_unavailable`
3386    #[serde(rename = "board_live_unavailable")]
3387    BoardLiveUnavailable,
3388    /// `board_upcoming_unavailable`
3389    #[serde(rename = "board_upcoming_unavailable")]
3390    BoardUpcomingUnavailable,
3391    /// `provider_unavailable`
3392    #[serde(rename = "provider_unavailable")]
3393    ProviderUnavailable,
3394    /// `holder_deadline_unavailable`
3395    #[serde(rename = "holder_deadline_unavailable")]
3396    HolderDeadlineUnavailable,
3397    /// `holder_computation_unavailable`
3398    #[serde(rename = "holder_computation_unavailable")]
3399    HolderComputationUnavailable,
3400    /// `missing_stored_market`
3401    #[serde(rename = "missing_stored_market")]
3402    MissingStoredMarket,
3403    /// `price_unavailable`
3404    #[serde(rename = "price_unavailable")]
3405    PriceUnavailable,
3406    /// `in_play_stale_observed`
3407    #[serde(rename = "in_play_stale_observed")]
3408    InPlayStaleObserved,
3409    /// `in_play_directional_unavailable`
3410    #[serde(rename = "in_play_directional_unavailable")]
3411    InPlayDirectionalUnavailable,
3412    /// `internal_unclassified`
3413    #[serde(rename = "internal_unclassified")]
3414    InternalUnclassified,
3415    /// `board_source_unavailable`
3416    #[serde(rename = "board_source_unavailable")]
3417    BoardSourceUnavailable,
3418    /// `board_deadline_unavailable`
3419    #[serde(rename = "board_deadline_unavailable")]
3420    BoardDeadlineUnavailable,
3421    /// A value this release does not know, kept as sent.
3422    #[serde(untagged)]
3423    Other(String),
3424}
3425
3426impl EdgeHunterObservationDegradationReasonReason {
3427    /// The value as the API spells it.
3428    pub fn as_str(&self) -> &str {
3429        match self {
3430            Self::HolderScanIncomplete => "holder_scan_incomplete",
3431            Self::LiveSourceStale => "live_source_stale",
3432            Self::DirectionalUnavailable => "directional_unavailable",
3433            Self::FunnelUnreconciled => "funnel_unreconciled",
3434            Self::BoardLiveUnavailable => "board_live_unavailable",
3435            Self::BoardUpcomingUnavailable => "board_upcoming_unavailable",
3436            Self::ProviderUnavailable => "provider_unavailable",
3437            Self::HolderDeadlineUnavailable => "holder_deadline_unavailable",
3438            Self::HolderComputationUnavailable => "holder_computation_unavailable",
3439            Self::MissingStoredMarket => "missing_stored_market",
3440            Self::PriceUnavailable => "price_unavailable",
3441            Self::InPlayStaleObserved => "in_play_stale_observed",
3442            Self::InPlayDirectionalUnavailable => "in_play_directional_unavailable",
3443            Self::InternalUnclassified => "internal_unclassified",
3444            Self::BoardSourceUnavailable => "board_source_unavailable",
3445            Self::BoardDeadlineUnavailable => "board_deadline_unavailable",
3446            Self::Other(value) => value,
3447        }
3448    }
3449}
3450
3451impl From<&str> for EdgeHunterObservationDegradationReasonReason {
3452    fn from(value: &str) -> Self {
3453        match value {
3454            "holder_scan_incomplete" => Self::HolderScanIncomplete,
3455            "live_source_stale" => Self::LiveSourceStale,
3456            "directional_unavailable" => Self::DirectionalUnavailable,
3457            "funnel_unreconciled" => Self::FunnelUnreconciled,
3458            "board_live_unavailable" => Self::BoardLiveUnavailable,
3459            "board_upcoming_unavailable" => Self::BoardUpcomingUnavailable,
3460            "provider_unavailable" => Self::ProviderUnavailable,
3461            "holder_deadline_unavailable" => Self::HolderDeadlineUnavailable,
3462            "holder_computation_unavailable" => Self::HolderComputationUnavailable,
3463            "missing_stored_market" => Self::MissingStoredMarket,
3464            "price_unavailable" => Self::PriceUnavailable,
3465            "in_play_stale_observed" => Self::InPlayStaleObserved,
3466            "in_play_directional_unavailable" => Self::InPlayDirectionalUnavailable,
3467            "internal_unclassified" => Self::InternalUnclassified,
3468            "board_source_unavailable" => Self::BoardSourceUnavailable,
3469            "board_deadline_unavailable" => Self::BoardDeadlineUnavailable,
3470            other => Self::Other(other.to_owned()),
3471        }
3472    }
3473}
3474
3475impl std::fmt::Display for EdgeHunterObservationDegradationReasonReason {
3476    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3477        f.write_str(self.as_str())
3478    }
3479}
3480
3481impl AsRef<str> for EdgeHunterObservationDegradationReasonReason {
3482    fn as_ref(&self) -> &str {
3483        self.as_str()
3484    }
3485}
3486
3487/// A market whose wider_holder card left this selection before kickoff, with why it left.
3488#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3489#[non_exhaustive]
3490pub struct EdgeHunterObservationDeparture {
3491    /// Raw Polymarket condition id.
3492    pub condition_id: String,
3493    #[serde(default)]
3494    pub event_slug: Option<String>,
3495    /// Canonical sport bucket the departed card carried.
3496    pub category: Category,
3497    /// The departed card's admitted_by: most_held_48h on an admission=most_held_48h response.
3498    pub admitted_by: AdmittedBy,
3499    /// Kickoff the departed card carried, in UTC. The entry leaves the list once it passes.
3500    pub game_start_time: String,
3501    /// The departed card's observed_at: when its last evaluation finished.
3502    pub last_observed_at: String,
3503    /// snapshot_as_of of the first snapshot of this selection without the card.
3504    pub departed_at: String,
3505    /// 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.
3506    pub reason: EdgeHunterObservationTerminalReason,
3507}
3508
3509/// 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.
3510///
3511/// A value this release does not know is kept in `Other`, so a new value never fails a response.
3512#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
3513#[non_exhaustive]
3514pub enum EdgeHunterObservationTerminalReason {
3515    /// `outside_horizon`
3516    #[serde(rename = "outside_horizon")]
3517    OutsideHorizon,
3518    /// `resolved`
3519    #[serde(rename = "resolved")]
3520    Resolved,
3521    /// `provider_closed`
3522    #[serde(rename = "provider_closed")]
3523    ProviderClosed,
3524    /// `provider_excluded`
3525    #[serde(rename = "provider_excluded")]
3526    ProviderExcluded,
3527    /// `invalid_market`
3528    #[serde(rename = "invalid_market")]
3529    InvalidMarket,
3530    /// `missing_token`
3531    #[serde(rename = "missing_token")]
3532    MissingToken,
3533    /// `missing_stored_market`
3534    #[serde(rename = "missing_stored_market")]
3535    MissingStoredMarket,
3536    /// `not_provider_live`
3537    #[serde(rename = "not_provider_live")]
3538    NotProviderLive,
3539    /// `board_source_unavailable`
3540    #[serde(rename = "board_source_unavailable")]
3541    BoardSourceUnavailable,
3542    /// `board_deadline_unavailable`
3543    #[serde(rename = "board_deadline_unavailable")]
3544    BoardDeadlineUnavailable,
3545    /// `primary_slate_candidate`
3546    #[serde(rename = "primary_slate_candidate")]
3547    PrimarySlateCandidate,
3548    /// `zero_indexed_holder_research`
3549    #[serde(rename = "zero_indexed_holder_research")]
3550    ZeroIndexedHolderResearch,
3551    /// `capacity_limited`
3552    #[serde(rename = "capacity_limited")]
3553    CapacityLimited,
3554    /// `provider_unavailable`
3555    #[serde(rename = "provider_unavailable")]
3556    ProviderUnavailable,
3557    /// `holder_deadline_unavailable`
3558    #[serde(rename = "holder_deadline_unavailable")]
3559    HolderDeadlineUnavailable,
3560    /// `holder_computation_unavailable`
3561    #[serde(rename = "holder_computation_unavailable")]
3562    HolderComputationUnavailable,
3563    /// `holder_scan_incomplete`
3564    #[serde(rename = "holder_scan_incomplete")]
3565    HolderScanIncomplete,
3566    /// `no_current_graded_holder`
3567    #[serde(rename = "no_current_graded_holder")]
3568    NoCurrentGradedHolder,
3569    /// `split_holder_pile`
3570    #[serde(rename = "split_holder_pile")]
3571    SplitHolderPile,
3572    /// `price_unavailable`
3573    #[serde(rename = "price_unavailable")]
3574    PriceUnavailable,
3575    /// `wider_holder_emitted`
3576    #[serde(rename = "wider_holder_emitted")]
3577    WiderHolderEmitted,
3578    /// `in_play_emitted`
3579    #[serde(rename = "in_play_emitted")]
3580    InPlayEmitted,
3581    /// `in_play_stale_observed`
3582    #[serde(rename = "in_play_stale_observed")]
3583    InPlayStaleObserved,
3584    /// `in_play_directional_unavailable`
3585    #[serde(rename = "in_play_directional_unavailable")]
3586    InPlayDirectionalUnavailable,
3587    /// `internal_unclassified`
3588    #[serde(rename = "internal_unclassified")]
3589    InternalUnclassified,
3590    /// A value this release does not know, kept as sent.
3591    #[serde(untagged)]
3592    Other(String),
3593}
3594
3595impl EdgeHunterObservationTerminalReason {
3596    /// The value as the API spells it.
3597    pub fn as_str(&self) -> &str {
3598        match self {
3599            Self::OutsideHorizon => "outside_horizon",
3600            Self::Resolved => "resolved",
3601            Self::ProviderClosed => "provider_closed",
3602            Self::ProviderExcluded => "provider_excluded",
3603            Self::InvalidMarket => "invalid_market",
3604            Self::MissingToken => "missing_token",
3605            Self::MissingStoredMarket => "missing_stored_market",
3606            Self::NotProviderLive => "not_provider_live",
3607            Self::BoardSourceUnavailable => "board_source_unavailable",
3608            Self::BoardDeadlineUnavailable => "board_deadline_unavailable",
3609            Self::PrimarySlateCandidate => "primary_slate_candidate",
3610            Self::ZeroIndexedHolderResearch => "zero_indexed_holder_research",
3611            Self::CapacityLimited => "capacity_limited",
3612            Self::ProviderUnavailable => "provider_unavailable",
3613            Self::HolderDeadlineUnavailable => "holder_deadline_unavailable",
3614            Self::HolderComputationUnavailable => "holder_computation_unavailable",
3615            Self::HolderScanIncomplete => "holder_scan_incomplete",
3616            Self::NoCurrentGradedHolder => "no_current_graded_holder",
3617            Self::SplitHolderPile => "split_holder_pile",
3618            Self::PriceUnavailable => "price_unavailable",
3619            Self::WiderHolderEmitted => "wider_holder_emitted",
3620            Self::InPlayEmitted => "in_play_emitted",
3621            Self::InPlayStaleObserved => "in_play_stale_observed",
3622            Self::InPlayDirectionalUnavailable => "in_play_directional_unavailable",
3623            Self::InternalUnclassified => "internal_unclassified",
3624            Self::Other(value) => value,
3625        }
3626    }
3627}
3628
3629impl From<&str> for EdgeHunterObservationTerminalReason {
3630    fn from(value: &str) -> Self {
3631        match value {
3632            "outside_horizon" => Self::OutsideHorizon,
3633            "resolved" => Self::Resolved,
3634            "provider_closed" => Self::ProviderClosed,
3635            "provider_excluded" => Self::ProviderExcluded,
3636            "invalid_market" => Self::InvalidMarket,
3637            "missing_token" => Self::MissingToken,
3638            "missing_stored_market" => Self::MissingStoredMarket,
3639            "not_provider_live" => Self::NotProviderLive,
3640            "board_source_unavailable" => Self::BoardSourceUnavailable,
3641            "board_deadline_unavailable" => Self::BoardDeadlineUnavailable,
3642            "primary_slate_candidate" => Self::PrimarySlateCandidate,
3643            "zero_indexed_holder_research" => Self::ZeroIndexedHolderResearch,
3644            "capacity_limited" => Self::CapacityLimited,
3645            "provider_unavailable" => Self::ProviderUnavailable,
3646            "holder_deadline_unavailable" => Self::HolderDeadlineUnavailable,
3647            "holder_computation_unavailable" => Self::HolderComputationUnavailable,
3648            "holder_scan_incomplete" => Self::HolderScanIncomplete,
3649            "no_current_graded_holder" => Self::NoCurrentGradedHolder,
3650            "split_holder_pile" => Self::SplitHolderPile,
3651            "price_unavailable" => Self::PriceUnavailable,
3652            "wider_holder_emitted" => Self::WiderHolderEmitted,
3653            "in_play_emitted" => Self::InPlayEmitted,
3654            "in_play_stale_observed" => Self::InPlayStaleObserved,
3655            "in_play_directional_unavailable" => Self::InPlayDirectionalUnavailable,
3656            "internal_unclassified" => Self::InternalUnclassified,
3657            other => Self::Other(other.to_owned()),
3658        }
3659    }
3660}
3661
3662impl std::fmt::Display for EdgeHunterObservationTerminalReason {
3663    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3664        f.write_str(self.as_str())
3665    }
3666}
3667
3668impl AsRef<str> for EdgeHunterObservationTerminalReason {
3669    fn as_ref(&self) -> &str {
3670        self.as_str()
3671    }
3672}
3673
3674/// 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.
3675#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3676#[non_exhaustive]
3677pub struct EdgeHunterObservationsResponse {
3678    pub object: String,
3679    pub view: String,
3680    pub data: Vec<EdgeHunterObservation>,
3681    pub has_more: bool,
3682    /// Pass as cursor for the next page. Always sent; null on the last page.
3683    #[serde(default)]
3684    pub next_cursor: Option<String>,
3685    /// Completion time of the shared observation snapshot pinned by the cursor.
3686    pub snapshot_as_of: String,
3687    /// 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.
3688    pub degraded: bool,
3689    /// 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.
3690    pub degradation_reasons: Vec<EdgeHunterObservationDegradationReason>,
3691    pub coverage: EdgeHunterObservationCoverage,
3692    pub funnel: EdgeHunterFunnelReport,
3693    pub meta: ResponseMeta,
3694    /// Normalized axes requested with a selector or category; omitted on an unselected default read.
3695    #[serde(default, skip_serializing_if = "Option::is_none")]
3696    pub selection: Option<EdgeHunterSelection>,
3697    /// 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.
3698    #[serde(default, skip_serializing_if = "Option::is_none")]
3699    pub admission: Option<Admission>,
3700    /// 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.
3701    #[serde(default, skip_serializing_if = "Option::is_none")]
3702    pub departures: Option<Vec<EdgeHunterObservationDeparture>>,
3703    /// 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.
3704    #[serde(default, skip_serializing_if = "Option::is_none")]
3705    pub signals_as_of: Option<String>,
3706}
3707
3708/// 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.
3709#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3710#[non_exhaustive]
3711pub struct EdgeHunterOutcome {
3712    pub index: i64,
3713    #[serde(default)]
3714    pub label: Option<String>,
3715    #[serde(default)]
3716    pub provider_id: Option<i64>,
3717    /// Frozen provider CLOB token ID for this exact outcome in YES/NO order. Null when unavailable; not a participant identity.
3718    #[serde(default)]
3719    pub token_id: Option<String>,
3720    #[serde(default)]
3721    pub current_price: Option<EdgeHunterPrice>,
3722}
3723
3724#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3725#[non_exhaustive]
3726pub struct EdgeHunterParticipant {
3727    #[serde(default, skip_serializing_if = "Option::is_none")]
3728    pub provider_id: Option<i64>,
3729    #[serde(default, skip_serializing_if = "Option::is_none")]
3730    pub logo: Option<String>,
3731    #[serde(default, skip_serializing_if = "Option::is_none")]
3732    pub logo_mark_dark: Option<bool>,
3733    #[serde(default, skip_serializing_if = "Option::is_none")]
3734    pub color: Option<String>,
3735    #[serde(default, skip_serializing_if = "Option::is_none")]
3736    pub headshot: Option<String>,
3737    #[serde(default, skip_serializing_if = "Option::is_none")]
3738    pub headshot_revision: Option<i64>,
3739    #[serde(default, skip_serializing_if = "Option::is_none")]
3740    pub tour: Option<String>,
3741    pub name: String,
3742    #[serde(default, skip_serializing_if = "Option::is_none")]
3743    pub logo_mark_light: Option<bool>,
3744    #[serde(default, skip_serializing_if = "Option::is_none")]
3745    pub logo_mark_measured: Option<bool>,
3746}
3747
3748#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3749#[non_exhaustive]
3750pub struct EdgeHunterPrice {
3751    /// Provider probability as a decimal string. Keep its precision until display.
3752    pub price: String,
3753    pub basis: EdgeHunterPriceBasis,
3754    /// Source observation clock in epoch milliseconds, represented as a string.
3755    pub ts: String,
3756    /// Backend validation clock in epoch milliseconds. Omitted when no current-source validation is available.
3757    #[serde(default, skip_serializing_if = "Option::is_none")]
3758    pub validated_at: Option<String>,
3759}
3760
3761/// A value this release does not know is kept in `Other`, so a new value never fails a response.
3762#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
3763#[non_exhaustive]
3764pub enum EdgeHunterPriceBasis {
3765    /// `midpoint`
3766    #[serde(rename = "midpoint")]
3767    Midpoint,
3768    /// `last_trade`
3769    #[serde(rename = "last_trade")]
3770    LastTrade,
3771    /// A value this release does not know, kept as sent.
3772    #[serde(untagged)]
3773    Other(String),
3774}
3775
3776impl EdgeHunterPriceBasis {
3777    /// The value as the API spells it.
3778    pub fn as_str(&self) -> &str {
3779        match self {
3780            Self::Midpoint => "midpoint",
3781            Self::LastTrade => "last_trade",
3782            Self::Other(value) => value,
3783        }
3784    }
3785}
3786
3787impl From<&str> for EdgeHunterPriceBasis {
3788    fn from(value: &str) -> Self {
3789        match value {
3790            "midpoint" => Self::Midpoint,
3791            "last_trade" => Self::LastTrade,
3792            other => Self::Other(other.to_owned()),
3793        }
3794    }
3795}
3796
3797impl std::fmt::Display for EdgeHunterPriceBasis {
3798    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3799        f.write_str(self.as_str())
3800    }
3801}
3802
3803impl AsRef<str> for EdgeHunterPriceBasis {
3804    fn as_ref(&self) -> &str {
3805        self.as_str()
3806    }
3807}
3808
3809/// 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.
3810#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3811#[non_exhaustive]
3812pub struct EdgeHunterRankedSignal {
3813    /// 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.
3814    #[serde(default)]
3815    pub side: Option<String>,
3816    /// UTC time at which the snapshot that ranked this row was computed. Canonical spelling of signal_created_at (#16310), same value.
3817    pub ranked_at: String,
3818    /// Recorded side backing score; higher values indicate stronger backing.
3819    pub backing_score: f64,
3820    /// 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.
3821    #[serde(default)]
3822    pub side_share: Option<f64>,
3823    /// Polymarket condition id.
3824    pub condition_id: String,
3825    /// 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.
3826    pub signal_created_at: String,
3827    /// Polymarket CLOB token id (ERC1155 asset id, decimal string) for the PILED outcome; null when unavailable.
3828    #[serde(default)]
3829    pub token_id: Option<String>,
3830    /// Canonical sport bucket (e.g. Basketball, Tennis); null when the raw category has no canonical mapping.
3831    #[serde(default)]
3832    pub category: Option<Category>,
3833    /// Raw provider category as stored (e.g. NBA, EPL).
3834    #[serde(default)]
3835    pub raw_category: Option<String>,
3836    #[serde(default)]
3837    pub title: Option<String>,
3838    #[serde(default)]
3839    pub event_slug: Option<String>,
3840    /// 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.
3841    #[serde(default)]
3842    pub game_start_time: Option<String>,
3843    /// 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.
3844    #[serde(default)]
3845    pub piled_side: Option<String>,
3846    /// 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.
3847    pub piled_outcome_index: i64,
3848    /// 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.
3849    #[serde(default)]
3850    pub sharp_pct: Option<f64>,
3851    /// Raw piled-side sharp-money USD.
3852    pub backed_sharp_usd: f64,
3853    /// S-grade graded holders on the piled side.
3854    pub s_count: i64,
3855    /// A-grade graded holders on the piled side.
3856    pub a_count: i64,
3857    /// B-grade graded holders on the piled side.
3858    pub b_count: i64,
3859    /// Piled-side graded holder count (s_count + a_count + b_count).
3860    pub graded_holders: i64,
3861    /// Best grade present on the piled side; null when none.
3862    #[serde(default)]
3863    pub top_grade: Option<MarketHolderGrade>,
3864    /// 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.
3865    #[serde(default)]
3866    pub smart_score: Option<f64>,
3867    /// Cumulative provider taker volume in shares, not cash or dollars.
3868    #[serde(default)]
3869    pub volume: Option<f64>,
3870    /// Aggregate recent flow direction on the market; null when unavailable.
3871    #[serde(default)]
3872    pub net_side: Option<Side>,
3873    /// Recorded conviction score; higher values indicate stronger conviction.
3874    pub conviction_score: f64,
3875    /// 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.
3876    #[serde(default)]
3877    pub one_way_holder_count: Option<i64>,
3878    /// 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.
3879    #[serde(default)]
3880    pub hedged_holder_count: Option<i64>,
3881    /// 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.
3882    #[serde(default)]
3883    pub one_way_graded_usd: Option<f64>,
3884    /// 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.
3885    #[serde(default)]
3886    pub directional_confidence: Option<f64>,
3887    /// Recorded side ordering score; higher values sort first.
3888    pub directional_rank_score: f64,
3889    pub category_skill: EdgeHunterCategorySkill,
3890    /// 1-based rank within the (min_grade-filtered) ranked result.
3891    pub rank: i64,
3892    /// Required nullable frozen metadata context. Null only during the legacy-generation transition; selected reads require sidecar readiness and fail closed with 503 instead.
3893    #[serde(default)]
3894    pub market_context: Option<EdgeHunterMarketContext>,
3895}
3896
3897/// 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.
3898#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3899#[non_exhaustive]
3900pub struct EdgeHunterRow {
3901    pub rank: i64,
3902    pub state: String,
3903    pub free: bool,
3904    pub condition_id: String,
3905    #[serde(default)]
3906    pub event_slug: Option<String>,
3907    #[serde(default)]
3908    pub title: Option<String>,
3909    #[serde(default)]
3910    pub category: Option<Category>,
3911    #[serde(default)]
3912    pub raw_category: Option<String>,
3913    #[serde(default)]
3914    pub game_start_time: Option<String>,
3915    /// Cumulative provider taker volume in shares, not cash in USD. Null when unavailable.
3916    #[serde(default)]
3917    pub volume: Option<f64>,
3918    pub participants: Vec<EdgeHunterParticipant>,
3919    #[serde(default)]
3920    pub image: Option<String>,
3921    pub outcomes: Vec<EdgeHunterOutcome>,
3922    #[serde(default)]
3923    pub signal: Option<EdgeHunterSignal>,
3924    /// Required nullable frozen metadata context. Null only during the legacy-generation transition; selected reads require sidecar readiness and fail closed with 503 instead.
3925    #[serde(default)]
3926    pub market_context: Option<EdgeHunterMarketContext>,
3927}
3928
3929/// 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.
3930#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3931#[non_exhaustive]
3932pub struct EdgeHunterSelection {
3933    #[serde(default, skip_serializing_if = "Option::is_none")]
3934    pub kind: Option<Kind>,
3935    /// Resolved legacy canonical bucket or non_sport for an unmappable category.
3936    #[serde(default, skip_serializing_if = "Option::is_none")]
3937    pub category: Option<String>,
3938    /// 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.
3939    #[serde(default, skip_serializing_if = "Option::is_none")]
3940    pub sports: Option<Vec<String>>,
3941    /// 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.
3942    #[serde(default, skip_serializing_if = "Option::is_none")]
3943    pub leagues: Option<Vec<String>>,
3944    /// 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.
3945    #[serde(default, skip_serializing_if = "Option::is_none")]
3946    pub market_types: Option<Vec<String>>,
3947    /// 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.
3948    #[serde(default, skip_serializing_if = "Option::is_none")]
3949    pub condition_ids: Option<Vec<String>>,
3950    /// Exact provider event slugs. Use event_slug returned on the row; no title or slug-prefix guessing.
3951    #[serde(default, skip_serializing_if = "Option::is_none")]
3952    pub event_slugs: Option<Vec<String>>,
3953    /// Exact provider series slugs. Read market_context.series_slug; a missing selected series excludes the row.
3954    #[serde(default, skip_serializing_if = "Option::is_none")]
3955    pub series_slugs: Option<Vec<String>>,
3956}
3957
3958/// 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.
3959#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3960#[non_exhaustive]
3961pub struct EdgeHunterSignal {
3962    #[serde(default)]
3963    pub piled_side: Option<String>,
3964    pub piled_outcome_index: i64,
3965    /// Fraction of graded money on the backed side, not a percentage from 0 to 100.
3966    #[serde(default)]
3967    pub sharp_pct: Option<f64>,
3968    pub backed_sharp_usd: f64,
3969    pub s_count: i64,
3970    pub a_count: i64,
3971    pub b_count: i64,
3972    pub graded_holders: i64,
3973    #[serde(default)]
3974    pub top_grade: Option<MarketHolderGrade>,
3975    #[serde(default)]
3976    pub smart_score: Option<f64>,
3977    #[serde(default)]
3978    pub net_side: Option<String>,
3979    pub conviction_score: f64,
3980    #[serde(default)]
3981    pub one_way_holder_count: Option<i64>,
3982    #[serde(default)]
3983    pub hedged_holder_count: Option<i64>,
3984    #[serde(default)]
3985    pub one_way_graded_usd: Option<f64>,
3986    #[serde(default)]
3987    pub directional_confidence: Option<f64>,
3988    pub directional_rank_score: f64,
3989    #[serde(default)]
3990    pub current_price: Option<EdgeHunterPrice>,
3991    /// 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.
3992    #[serde(default)]
3993    pub token_id: Option<String>,
3994    /// 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.
3995    pub ranked_at: String,
3996    /// 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.
3997    pub category_skill: EdgeHunterCategorySkill,
3998}
3999
4000/// Full Edge Hunter signals list envelope. The view literal distinguishes advanced collections, including empty pages.
4001#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4002#[non_exhaustive]
4003pub struct EdgeHunterSignalsResponse {
4004    pub object: String,
4005    pub view: String,
4006    pub data: Vec<EdgeHunterRankedSignal>,
4007    pub has_more: bool,
4008    #[serde(default, skip_serializing_if = "Option::is_none")]
4009    pub next_cursor: Option<String>,
4010    #[serde(default, skip_serializing_if = "Option::is_none")]
4011    pub total: Option<i64>,
4012    pub meta: ResponseMeta,
4013    /// Normalized axes requested with a selector or category; omitted on an unselected default read.
4014    #[serde(default, skip_serializing_if = "Option::is_none")]
4015    pub selection: Option<EdgeHunterSelection>,
4016}
4017
4018/// Independent sports-board supply plus stored-universe terminal accounting for one canonical sport.
4019#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4020#[non_exhaustive]
4021pub struct EdgeHunterSportFunnelReport {
4022    pub sport: Category,
4023    /// Unique condition ids independently visible on the provider-first sports board.
4024    pub board_input: i64,
4025    /// 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.
4026    pub board_live_available: bool,
4027    /// Whether a provider-backed upcoming-board source is configured and applicable for this sport. False means not applicable, not provider failure.
4028    pub board_upcoming_configured: bool,
4029    /// 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.
4030    pub board_upcoming_available: bool,
4031    /// 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.
4032    pub board_upcoming_status: BoardUpcomingStatus,
4033    /// 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.
4034    pub board_upcoming_unavailable_scopes: Vec<BoardUpcomingUnavailableScopes>,
4035    /// Stored-universe rows plus provider-board rows missing from storage.
4036    pub input: i64,
4037    /// 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.
4038    pub terminals: std::collections::BTreeMap<String, i64>,
4039    /// Sum of every sparse terminal count.
4040    pub terminal_total: i64,
4041    /// True exactly when input equals terminal_total.
4042    pub reconciled: bool,
4043}
4044
4045/// A value this release does not know is kept in `Other`, so a new value never fails a response.
4046#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
4047#[non_exhaustive]
4048pub enum EnrichmentStatus {
4049    /// `available`
4050    #[serde(rename = "available")]
4051    Available,
4052    /// `unavailable`
4053    #[serde(rename = "unavailable")]
4054    Unavailable,
4055    /// A value this release does not know, kept as sent.
4056    #[serde(untagged)]
4057    Other(String),
4058}
4059
4060impl EnrichmentStatus {
4061    /// The value as the API spells it.
4062    pub fn as_str(&self) -> &str {
4063        match self {
4064            Self::Available => "available",
4065            Self::Unavailable => "unavailable",
4066            Self::Other(value) => value,
4067        }
4068    }
4069}
4070
4071impl From<&str> for EnrichmentStatus {
4072    fn from(value: &str) -> Self {
4073        match value {
4074            "available" => Self::Available,
4075            "unavailable" => Self::Unavailable,
4076            other => Self::Other(other.to_owned()),
4077        }
4078    }
4079}
4080
4081impl std::fmt::Display for EnrichmentStatus {
4082    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4083        f.write_str(self.as_str())
4084    }
4085}
4086
4087impl AsRef<str> for EnrichmentStatus {
4088    fn as_ref(&self) -> &str {
4089        self.as_str()
4090    }
4091}
4092
4093/// A value this release does not know is kept in `Other`, so a new value never fails a response.
4094#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
4095#[non_exhaustive]
4096pub enum ErrorCode {
4097    /// `bad_request`
4098    #[serde(rename = "bad_request")]
4099    BadRequest,
4100    /// `invalid_api_key`
4101    #[serde(rename = "invalid_api_key")]
4102    InvalidApiKey,
4103    /// `subscription_required`
4104    #[serde(rename = "subscription_required")]
4105    SubscriptionRequired,
4106    /// `forbidden`
4107    #[serde(rename = "forbidden")]
4108    Forbidden,
4109    /// `insufficient_scope`
4110    #[serde(rename = "insufficient_scope")]
4111    InsufficientScope,
4112    /// `not_found`
4113    #[serde(rename = "not_found")]
4114    NotFound,
4115    /// `account_locked`
4116    #[serde(rename = "account_locked")]
4117    AccountLocked,
4118    /// `rate_limited`
4119    #[serde(rename = "rate_limited")]
4120    RateLimited,
4121    /// `rate_limit_unavailable`
4122    #[serde(rename = "rate_limit_unavailable")]
4123    RateLimitUnavailable,
4124    /// `internal_error`
4125    #[serde(rename = "internal_error")]
4126    InternalError,
4127    /// `request_timeout`
4128    #[serde(rename = "request_timeout")]
4129    RequestTimeout,
4130    /// `endpoint_retired`
4131    #[serde(rename = "endpoint_retired")]
4132    EndpointRetired,
4133    /// A value this release does not know, kept as sent.
4134    #[serde(untagged)]
4135    Other(String),
4136}
4137
4138impl ErrorCode {
4139    /// The value as the API spells it.
4140    pub fn as_str(&self) -> &str {
4141        match self {
4142            Self::BadRequest => "bad_request",
4143            Self::InvalidApiKey => "invalid_api_key",
4144            Self::SubscriptionRequired => "subscription_required",
4145            Self::Forbidden => "forbidden",
4146            Self::InsufficientScope => "insufficient_scope",
4147            Self::NotFound => "not_found",
4148            Self::AccountLocked => "account_locked",
4149            Self::RateLimited => "rate_limited",
4150            Self::RateLimitUnavailable => "rate_limit_unavailable",
4151            Self::InternalError => "internal_error",
4152            Self::RequestTimeout => "request_timeout",
4153            Self::EndpointRetired => "endpoint_retired",
4154            Self::Other(value) => value,
4155        }
4156    }
4157}
4158
4159impl From<&str> for ErrorCode {
4160    fn from(value: &str) -> Self {
4161        match value {
4162            "bad_request" => Self::BadRequest,
4163            "invalid_api_key" => Self::InvalidApiKey,
4164            "subscription_required" => Self::SubscriptionRequired,
4165            "forbidden" => Self::Forbidden,
4166            "insufficient_scope" => Self::InsufficientScope,
4167            "not_found" => Self::NotFound,
4168            "account_locked" => Self::AccountLocked,
4169            "rate_limited" => Self::RateLimited,
4170            "rate_limit_unavailable" => Self::RateLimitUnavailable,
4171            "internal_error" => Self::InternalError,
4172            "request_timeout" => Self::RequestTimeout,
4173            "endpoint_retired" => Self::EndpointRetired,
4174            other => Self::Other(other.to_owned()),
4175        }
4176    }
4177}
4178
4179impl std::fmt::Display for ErrorCode {
4180    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4181        f.write_str(self.as_str())
4182    }
4183}
4184
4185impl AsRef<str> for ErrorCode {
4186    fn as_ref(&self) -> &str {
4187        self.as_str()
4188    }
4189}
4190
4191/// A value this release does not know is kept in `Other`, so a new value never fails a response.
4192#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
4193#[non_exhaustive]
4194pub enum ErrorReason {
4195    /// `cursor_expired`
4196    #[serde(rename = "cursor_expired")]
4197    CursorExpired,
4198    /// `unknown_endpoint`
4199    #[serde(rename = "unknown_endpoint")]
4200    UnknownEndpoint,
4201    /// `pick_not_released`
4202    #[serde(rename = "pick_not_released")]
4203    PickNotReleased,
4204    /// `trader_not_tracked`
4205    #[serde(rename = "trader_not_tracked")]
4206    TraderNotTracked,
4207    /// `market_out_of_scope`
4208    #[serde(rename = "market_out_of_scope")]
4209    MarketOutOfScope,
4210    /// `read_model_warming`
4211    #[serde(rename = "read_model_warming")]
4212    ReadModelWarming,
4213    /// `database_unavailable`
4214    #[serde(rename = "database_unavailable")]
4215    DatabaseUnavailable,
4216    /// `request_accounting_unavailable`
4217    #[serde(rename = "request_accounting_unavailable")]
4218    RequestAccountingUnavailable,
4219    /// `idempotency_in_progress`
4220    #[serde(rename = "idempotency_in_progress")]
4221    IdempotencyInProgress,
4222    /// `webhook_delivery_in_progress`
4223    #[serde(rename = "webhook_delivery_in_progress")]
4224    WebhookDeliveryInProgress,
4225    /// `webhook_secret_rotation_not_prepared`
4226    #[serde(rename = "webhook_secret_rotation_not_prepared")]
4227    WebhookSecretRotationNotPrepared,
4228    /// `webhook_secret_rotation_overlap_active`
4229    #[serde(rename = "webhook_secret_rotation_overlap_active")]
4230    WebhookSecretRotationOverlapActive,
4231    /// `sandbox_api_key`
4232    #[serde(rename = "sandbox_api_key")]
4233    SandboxApiKey,
4234    /// `api_key_in_query`
4235    #[serde(rename = "api_key_in_query")]
4236    ApiKeyInQuery,
4237    /// `subscription_inactive`
4238    #[serde(rename = "subscription_inactive")]
4239    SubscriptionInactive,
4240    /// `payment_overdue`
4241    #[serde(rename = "payment_overdue")]
4242    PaymentOverdue,
4243    /// `monthly_quota_exceeded`
4244    #[serde(rename = "monthly_quota_exceeded")]
4245    MonthlyQuotaExceeded,
4246    /// `invalid_query`
4247    #[serde(rename = "invalid_query")]
4248    InvalidQuery,
4249    /// `unknown_query_parameter`
4250    #[serde(rename = "unknown_query_parameter")]
4251    UnknownQueryParameter,
4252    /// `invalid_path`
4253    #[serde(rename = "invalid_path")]
4254    InvalidPath,
4255    /// `invalid_body`
4256    #[serde(rename = "invalid_body")]
4257    InvalidBody,
4258    /// `unsupported_media_type`
4259    #[serde(rename = "unsupported_media_type")]
4260    UnsupportedMediaType,
4261    /// `payload_too_large`
4262    #[serde(rename = "payload_too_large")]
4263    PayloadTooLarge,
4264    /// `method_not_allowed`
4265    #[serde(rename = "method_not_allowed")]
4266    MethodNotAllowed,
4267    /// `ip_rate_limited`
4268    #[serde(rename = "ip_rate_limited")]
4269    IpRateLimited,
4270    /// `ip_throttled`
4271    #[serde(rename = "ip_throttled")]
4272    IpThrottled,
4273    /// `cold_read_limited`
4274    #[serde(rename = "cold_read_limited")]
4275    ColdReadLimited,
4276    /// `export_expired`
4277    #[serde(rename = "export_expired")]
4278    ExportExpired,
4279    /// `freshness_ceiling_unsatisfied`
4280    #[serde(rename = "freshness_ceiling_unsatisfied")]
4281    FreshnessCeilingUnsatisfied,
4282    /// `max_plan_required`
4283    #[serde(rename = "max_plan_required")]
4284    MaxPlanRequired,
4285    /// `endpoint_retired`
4286    #[serde(rename = "endpoint_retired")]
4287    EndpointRetired,
4288    /// A value this release does not know, kept as sent.
4289    #[serde(untagged)]
4290    Other(String),
4291}
4292
4293impl ErrorReason {
4294    /// The value as the API spells it.
4295    pub fn as_str(&self) -> &str {
4296        match self {
4297            Self::CursorExpired => "cursor_expired",
4298            Self::UnknownEndpoint => "unknown_endpoint",
4299            Self::PickNotReleased => "pick_not_released",
4300            Self::TraderNotTracked => "trader_not_tracked",
4301            Self::MarketOutOfScope => "market_out_of_scope",
4302            Self::ReadModelWarming => "read_model_warming",
4303            Self::DatabaseUnavailable => "database_unavailable",
4304            Self::RequestAccountingUnavailable => "request_accounting_unavailable",
4305            Self::IdempotencyInProgress => "idempotency_in_progress",
4306            Self::WebhookDeliveryInProgress => "webhook_delivery_in_progress",
4307            Self::WebhookSecretRotationNotPrepared => "webhook_secret_rotation_not_prepared",
4308            Self::WebhookSecretRotationOverlapActive => "webhook_secret_rotation_overlap_active",
4309            Self::SandboxApiKey => "sandbox_api_key",
4310            Self::ApiKeyInQuery => "api_key_in_query",
4311            Self::SubscriptionInactive => "subscription_inactive",
4312            Self::PaymentOverdue => "payment_overdue",
4313            Self::MonthlyQuotaExceeded => "monthly_quota_exceeded",
4314            Self::InvalidQuery => "invalid_query",
4315            Self::UnknownQueryParameter => "unknown_query_parameter",
4316            Self::InvalidPath => "invalid_path",
4317            Self::InvalidBody => "invalid_body",
4318            Self::UnsupportedMediaType => "unsupported_media_type",
4319            Self::PayloadTooLarge => "payload_too_large",
4320            Self::MethodNotAllowed => "method_not_allowed",
4321            Self::IpRateLimited => "ip_rate_limited",
4322            Self::IpThrottled => "ip_throttled",
4323            Self::ColdReadLimited => "cold_read_limited",
4324            Self::ExportExpired => "export_expired",
4325            Self::FreshnessCeilingUnsatisfied => "freshness_ceiling_unsatisfied",
4326            Self::MaxPlanRequired => "max_plan_required",
4327            Self::EndpointRetired => "endpoint_retired",
4328            Self::Other(value) => value,
4329        }
4330    }
4331}
4332
4333impl From<&str> for ErrorReason {
4334    fn from(value: &str) -> Self {
4335        match value {
4336            "cursor_expired" => Self::CursorExpired,
4337            "unknown_endpoint" => Self::UnknownEndpoint,
4338            "pick_not_released" => Self::PickNotReleased,
4339            "trader_not_tracked" => Self::TraderNotTracked,
4340            "market_out_of_scope" => Self::MarketOutOfScope,
4341            "read_model_warming" => Self::ReadModelWarming,
4342            "database_unavailable" => Self::DatabaseUnavailable,
4343            "request_accounting_unavailable" => Self::RequestAccountingUnavailable,
4344            "idempotency_in_progress" => Self::IdempotencyInProgress,
4345            "webhook_delivery_in_progress" => Self::WebhookDeliveryInProgress,
4346            "webhook_secret_rotation_not_prepared" => Self::WebhookSecretRotationNotPrepared,
4347            "webhook_secret_rotation_overlap_active" => Self::WebhookSecretRotationOverlapActive,
4348            "sandbox_api_key" => Self::SandboxApiKey,
4349            "api_key_in_query" => Self::ApiKeyInQuery,
4350            "subscription_inactive" => Self::SubscriptionInactive,
4351            "payment_overdue" => Self::PaymentOverdue,
4352            "monthly_quota_exceeded" => Self::MonthlyQuotaExceeded,
4353            "invalid_query" => Self::InvalidQuery,
4354            "unknown_query_parameter" => Self::UnknownQueryParameter,
4355            "invalid_path" => Self::InvalidPath,
4356            "invalid_body" => Self::InvalidBody,
4357            "unsupported_media_type" => Self::UnsupportedMediaType,
4358            "payload_too_large" => Self::PayloadTooLarge,
4359            "method_not_allowed" => Self::MethodNotAllowed,
4360            "ip_rate_limited" => Self::IpRateLimited,
4361            "ip_throttled" => Self::IpThrottled,
4362            "cold_read_limited" => Self::ColdReadLimited,
4363            "export_expired" => Self::ExportExpired,
4364            "freshness_ceiling_unsatisfied" => Self::FreshnessCeilingUnsatisfied,
4365            "max_plan_required" => Self::MaxPlanRequired,
4366            "endpoint_retired" => Self::EndpointRetired,
4367            other => Self::Other(other.to_owned()),
4368        }
4369    }
4370}
4371
4372impl std::fmt::Display for ErrorReason {
4373    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4374        f.write_str(self.as_str())
4375    }
4376}
4377
4378impl AsRef<str> for ErrorReason {
4379    fn as_ref(&self) -> &str {
4380        self.as_str()
4381    }
4382}
4383
4384#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4385#[non_exhaustive]
4386pub struct EventReplayEvent {
4387    /// Opaque event identity: the ef_-encoded whale_alerts.id, stable across cursor formats. Deduplicate on this, never on cursor or sequence.
4388    pub id: String,
4389    pub r#type: String,
4390    /// 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.
4391    pub cursor: String,
4392    /// 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.
4393    pub sequence: i64,
4394    pub published_at: String,
4395    /// 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.
4396    pub payload: EventReplayEventPayload,
4397    /// 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).
4398    #[serde(default, skip_serializing_if = "Option::is_none")]
4399    pub trade: Option<LargeTrade>,
4400    pub source: EventReplaySource,
4401    pub freshness: EventReplayFreshness,
4402}
4403
4404/// 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.
4405#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4406#[non_exhaustive]
4407pub struct EventReplayEventPayload {
4408    /// Whale trades this event announces. One event is minted per stored whale trade, so this is 1.
4409    pub count: i64,
4410    /// 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.
4411    pub whale_alert_id: i64,
4412    /// The Polymarket condition id of the market the trade was in.
4413    pub condition_id: String,
4414    /// 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.
4415    pub trader_id: i64,
4416    /// Provider discriminator. Polymarket only.
4417    pub platform: String,
4418    /// Keys this release does not name. The API adds fields additively; they are kept here.
4419    #[serde(flatten)]
4420    pub extra: serde_json::Map<String, serde_json::Value>,
4421}
4422
4423#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4424#[non_exhaustive]
4425pub struct EventReplayFreshness {
4426    pub status: String,
4427    pub observed_at: String,
4428}
4429
4430#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4431#[non_exhaustive]
4432pub struct EventReplayMeta {
4433    /// 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.
4434    pub request_id: String,
4435    pub cached: bool,
4436    /// Advisory request weight (relative compute cost). 1 for simple reads; higher for heavier endpoints. Not a credit/price.
4437    pub cost: i64,
4438    pub replay: EventReplayMetaReplay,
4439    pub retention: EventReplayMetaRetention,
4440    pub completeness: EventReplayMetaCompleteness,
4441}
4442
4443#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4444#[non_exhaustive]
4445pub struct EventReplayMetaCompleteness {
4446    /// 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.
4447    pub status: EventReplayMetaCompletenessStatus,
4448    pub reason: String,
4449}
4450
4451/// A value this release does not know is kept in `Other`, so a new value never fails a response.
4452#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
4453#[non_exhaustive]
4454pub enum EventReplayMetaCompletenessStatus {
4455    /// `complete`
4456    #[serde(rename = "complete")]
4457    Complete,
4458    /// `caught_up`
4459    #[serde(rename = "caught_up")]
4460    CaughtUp,
4461    /// A value this release does not know, kept as sent.
4462    #[serde(untagged)]
4463    Other(String),
4464}
4465
4466impl EventReplayMetaCompletenessStatus {
4467    /// The value as the API spells it.
4468    pub fn as_str(&self) -> &str {
4469        match self {
4470            Self::Complete => "complete",
4471            Self::CaughtUp => "caught_up",
4472            Self::Other(value) => value,
4473        }
4474    }
4475}
4476
4477impl From<&str> for EventReplayMetaCompletenessStatus {
4478    fn from(value: &str) -> Self {
4479        match value {
4480            "complete" => Self::Complete,
4481            "caught_up" => Self::CaughtUp,
4482            other => Self::Other(other.to_owned()),
4483        }
4484    }
4485}
4486
4487impl std::fmt::Display for EventReplayMetaCompletenessStatus {
4488    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4489        f.write_str(self.as_str())
4490    }
4491}
4492
4493impl AsRef<str> for EventReplayMetaCompletenessStatus {
4494    fn as_ref(&self) -> &str {
4495        self.as_str()
4496    }
4497}
4498
4499#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4500#[non_exhaustive]
4501pub struct EventReplayMetaReplay {
4502    /// The request cursor in canonical form (an id-only cursor is re-encoded), or the zero position when omitted.
4503    pub from_cursor: String,
4504    /// 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.
4505    pub to_cursor: String,
4506    /// whale_alerts.id component of the request cursor (0 when omitted).
4507    pub from_sequence: i64,
4508    /// 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.
4509    pub to_sequence: i64,
4510    /// 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).
4511    pub ordering: String,
4512    /// 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.
4513    pub pending_beyond_horizon: bool,
4514    /// The effective filter set this page ran with and next_cursor is bound to. Absent on an unfiltered walk.
4515    #[serde(default, skip_serializing_if = "Option::is_none")]
4516    pub filters: Option<EventReplayMetaReplayFilters>,
4517    /// The expansions applied to every event on this page; empty when none.
4518    pub expand: Vec<String>,
4519}
4520
4521/// The effective filter set this page ran with and next_cursor is bound to. Absent on an unfiltered walk.
4522#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4523#[non_exhaustive]
4524pub struct EventReplayMetaReplayFilters {
4525    /// The trader parameter as given.
4526    #[serde(default, skip_serializing_if = "Option::is_none")]
4527    pub trader: Option<String>,
4528    /// The raw provider condition id after mkt_ is stripped.
4529    #[serde(default, skip_serializing_if = "Option::is_none")]
4530    pub condition_id: Option<String>,
4531    #[serde(default, skip_serializing_if = "Option::is_none")]
4532    pub min_grade: Option<Grade>,
4533    #[serde(default, skip_serializing_if = "Option::is_none")]
4534    pub min_size: Option<f64>,
4535}
4536
4537#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4538#[non_exhaustive]
4539pub struct EventReplayMetaRetention {
4540    pub status: String,
4541    pub retained_events: i64,
4542    pub cursor_expired: bool,
4543}
4544
4545#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4546#[non_exhaustive]
4547pub struct EventReplaySource {
4548    pub kind: String,
4549    pub producer_family: String,
4550    pub owner: String,
4551    pub provider_fetch_at_request_time: bool,
4552}
4553
4554/// 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.
4555#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4556#[non_exhaustive]
4557pub struct ExactDecimal {
4558    /// 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.
4559    pub value: String,
4560    /// Unit of the value, such as `USD`, `USD/share`, or `shares`.
4561    pub unit: String,
4562    /// Number of digits after the decimal point in `value`'s source atom.
4563    pub scale: i64,
4564    /// Backend-owned source or derivation basis. Treat it as provenance, not as a display label.
4565    pub basis: String,
4566}
4567
4568/// A value this release does not know is kept in `Other`, so a new value never fails a response.
4569#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
4570#[non_exhaustive]
4571pub enum ExchangeFamily {
4572    /// `ctf_v2`
4573    #[serde(rename = "ctf_v2")]
4574    CtfV2,
4575    /// `neg_risk_ctf_v2`
4576    #[serde(rename = "neg_risk_ctf_v2")]
4577    NegRiskCtfV2,
4578    /// `exchange_v3`
4579    #[serde(rename = "exchange_v3")]
4580    ExchangeV3,
4581    /// A value this release does not know, kept as sent.
4582    #[serde(untagged)]
4583    Other(String),
4584}
4585
4586impl ExchangeFamily {
4587    /// The value as the API spells it.
4588    pub fn as_str(&self) -> &str {
4589        match self {
4590            Self::CtfV2 => "ctf_v2",
4591            Self::NegRiskCtfV2 => "neg_risk_ctf_v2",
4592            Self::ExchangeV3 => "exchange_v3",
4593            Self::Other(value) => value,
4594        }
4595    }
4596}
4597
4598impl From<&str> for ExchangeFamily {
4599    fn from(value: &str) -> Self {
4600        match value {
4601            "ctf_v2" => Self::CtfV2,
4602            "neg_risk_ctf_v2" => Self::NegRiskCtfV2,
4603            "exchange_v3" => Self::ExchangeV3,
4604            other => Self::Other(other.to_owned()),
4605        }
4606    }
4607}
4608
4609impl std::fmt::Display for ExchangeFamily {
4610    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4611        f.write_str(self.as_str())
4612    }
4613}
4614
4615impl AsRef<str> for ExchangeFamily {
4616    fn as_ref(&self) -> &str {
4617        self.as_str()
4618    }
4619}
4620
4621/// A value this release does not know is kept in `Other`, so a new value never fails a response.
4622#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
4623#[non_exhaustive]
4624pub enum Expand {
4625    /// `strategy`
4626    #[serde(rename = "strategy")]
4627    Strategy,
4628    /// `categories`
4629    #[serde(rename = "categories")]
4630    Categories,
4631    /// `quant_metrics`
4632    #[serde(rename = "quant_metrics")]
4633    QuantMetrics,
4634    /// `trust`
4635    #[serde(rename = "trust")]
4636    Trust,
4637    /// `breakdowns`
4638    #[serde(rename = "breakdowns")]
4639    Breakdowns,
4640    /// A value this release does not know, kept as sent.
4641    #[serde(untagged)]
4642    Other(String),
4643}
4644
4645impl Expand {
4646    /// The value as the API spells it.
4647    pub fn as_str(&self) -> &str {
4648        match self {
4649            Self::Strategy => "strategy",
4650            Self::Categories => "categories",
4651            Self::QuantMetrics => "quant_metrics",
4652            Self::Trust => "trust",
4653            Self::Breakdowns => "breakdowns",
4654            Self::Other(value) => value,
4655        }
4656    }
4657}
4658
4659impl From<&str> for Expand {
4660    fn from(value: &str) -> Self {
4661        match value {
4662            "strategy" => Self::Strategy,
4663            "categories" => Self::Categories,
4664            "quant_metrics" => Self::QuantMetrics,
4665            "trust" => Self::Trust,
4666            "breakdowns" => Self::Breakdowns,
4667            other => Self::Other(other.to_owned()),
4668        }
4669    }
4670}
4671
4672impl std::fmt::Display for Expand {
4673    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4674        f.write_str(self.as_str())
4675    }
4676}
4677
4678impl AsRef<str> for Expand {
4679    fn as_ref(&self) -> &str {
4680        self.as_str()
4681    }
4682}
4683
4684/// Discriminated by `type`. A `type` this release does not know is kept whole in
4685/// `Unknown`, so a new kind never fails a response.
4686#[derive(Debug, Clone, PartialEq)]
4687#[non_exhaustive]
4688pub enum ExploreEntry {
4689    /// `type` is `group`.
4690    Group(ExploreGroup),
4691    /// `type` is `standalone`.
4692    Standalone(ExploreStandalone),
4693    /// A `type` this release does not know, kept as sent.
4694    Unknown(serde_json::Value),
4695}
4696
4697impl<'de> Deserialize<'de> for ExploreEntry {
4698    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
4699        let value = serde_json::Value::deserialize(deserializer)?;
4700        match value.get("type").and_then(serde_json::Value::as_str) {
4701            Some("group") => serde_json::from_value(value)
4702                .map(Self::Group)
4703                .map_err(de::Error::custom),
4704            Some("standalone") => serde_json::from_value(value)
4705                .map(Self::Standalone)
4706                .map_err(de::Error::custom),
4707            _ => Ok(Self::Unknown(value)),
4708        }
4709    }
4710}
4711
4712impl Serialize for ExploreEntry {
4713    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
4714        match self {
4715            Self::Group(inner) => inner.serialize(serializer),
4716            Self::Standalone(inner) => inner.serialize(serializer),
4717            Self::Unknown(inner) => inner.serialize(serializer),
4718        }
4719    }
4720}
4721
4722#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4723#[non_exhaustive]
4724pub struct ExploreFacetValue {
4725    pub value: String,
4726    pub label: String,
4727    pub count: i64,
4728}
4729
4730#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4731#[non_exhaustive]
4732pub struct ExploreFacets {
4733    pub categories: Vec<ExploreFacetValue>,
4734    pub platforms: Vec<ExploreFacetValue>,
4735}
4736
4737#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4738#[non_exhaustive]
4739pub struct ExploreGroup {
4740    pub r#type: String,
4741    pub event_slug: String,
4742    pub parent_title: String,
4743    #[serde(default)]
4744    pub image: Option<String>,
4745    /// Provider platform. Always polymarket, or null when the row carries no stored value.
4746    #[serde(default)]
4747    pub platform: Option<String>,
4748    #[serde(default)]
4749    pub category: Option<String>,
4750    /// 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.
4751    pub markets: Vec<ExploreMarket>,
4752    /// 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.
4753    #[serde(default)]
4754    pub rep_volume: Option<f64>,
4755    /// 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).
4756    #[serde(default)]
4757    pub rep_large_trades: Option<i64>,
4758    /// 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.
4759    #[serde(default)]
4760    pub rep_whales: Option<i64>,
4761}
4762
4763#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4764#[non_exhaustive]
4765pub struct ExploreMarket {
4766    pub id: String,
4767    pub condition_id: String,
4768    /// Non-empty market title.
4769    pub title: String,
4770    /// Provider-native market slug.
4771    #[serde(default)]
4772    pub slug: Option<String>,
4773    /// First-party market page slug used for internal links.
4774    #[serde(default)]
4775    pub url_slug: Option<String>,
4776    #[serde(default)]
4777    pub image: Option<String>,
4778    #[serde(default)]
4779    pub icon: Option<String>,
4780    #[serde(default)]
4781    pub category: Option<String>,
4782    /// Provider platform. Always polymarket, or null when the row carries no stored value.
4783    #[serde(default)]
4784    pub platform: Option<String>,
4785    /// 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.
4786    pub status: MarketSearchResultStatus,
4787    /// 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.
4788    #[serde(default)]
4789    pub volume: Option<f64>,
4790    #[serde(default)]
4791    pub liquidity: Option<f64>,
4792    /// 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).
4793    #[serde(default)]
4794    pub large_trade_count: Option<i64>,
4795    /// 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.
4796    #[serde(default)]
4797    pub whale_trade_count: Option<i64>,
4798    /// 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).
4799    #[serde(default)]
4800    pub large_trade_distinct_wallets: Option<i64>,
4801    /// 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.
4802    #[serde(default)]
4803    pub whale_distinct_wallets: Option<i64>,
4804    /// 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).
4805    #[serde(default)]
4806    pub large_trade_total_usd: Option<f64>,
4807    /// 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.
4808    #[serde(default)]
4809    pub whale_total_usd: Option<f64>,
4810    /// 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).
4811    #[serde(default)]
4812    pub large_trade_last_at: Option<String>,
4813    /// 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.
4814    #[serde(default)]
4815    pub whale_last_trade_at: Option<String>,
4816    #[serde(default)]
4817    pub end_date: Option<String>,
4818    #[serde(default)]
4819    pub created_at: Option<String>,
4820    #[serde(default)]
4821    pub outcome_yes: Option<String>,
4822    /// The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the YES outcome; null when unavailable (e.g. unsynced markets).
4823    #[serde(default)]
4824    pub token_id_yes: Option<String>,
4825    #[serde(default)]
4826    pub outcome_no: Option<String>,
4827    /// The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the NO outcome; null when unavailable (e.g. unsynced markets).
4828    #[serde(default)]
4829    pub token_id_no: Option<String>,
4830    #[serde(default)]
4831    pub event_slug: Option<String>,
4832    #[serde(default)]
4833    pub smart_score: Option<f64>,
4834    #[serde(default)]
4835    pub smart_count: Option<i64>,
4836    /// 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.
4837    #[serde(default)]
4838    pub smart_label: Option<String>,
4839    /// 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.
4840    #[serde(default)]
4841    pub sharp_money_as_of: Option<String>,
4842    /// Display label for the YES/outcome_index=0 side, enriched from provider outcome metadata when available.
4843    #[serde(default)]
4844    pub outcome_yes_label: Option<String>,
4845    /// Display label for the NO/outcome_index=1 side, enriched from provider outcome metadata when available.
4846    #[serde(default)]
4847    pub outcome_no_label: Option<String>,
4848    /// Provider-owned YES/outcome_index=0 identifier when available for trade-ticket wiring.
4849    #[serde(default)]
4850    pub outcome_yes_provider_id: Option<i64>,
4851    /// Provider-owned NO/outcome_index=1 identifier when available for trade-ticket wiring.
4852    #[serde(default)]
4853    pub outcome_no_provider_id: Option<i64>,
4854    #[serde(default)]
4855    pub open_interest: Option<f64>,
4856    #[serde(default)]
4857    pub oi_change_pct: Option<f64>,
4858    #[serde(default)]
4859    pub price_points: Option<Vec<Vec<f64>>>,
4860    #[serde(default)]
4861    pub no_price_points: Option<Vec<Vec<f64>>>,
4862    #[serde(default)]
4863    pub last_price: Option<f64>,
4864    #[serde(default)]
4865    pub no_last_price: Option<f64>,
4866    #[serde(default)]
4867    pub change_pct_24h: Option<f64>,
4868    #[serde(default)]
4869    pub no_change_pct_24h: Option<f64>,
4870    /// Backend-owned deterministic market discovery score used by the hot sort.
4871    #[serde(default)]
4872    pub discover_score: Option<f64>,
4873    pub score_components: ExploreMarketScoreComponents,
4874    pub freshness: ExploreMarketFreshness,
4875}
4876
4877#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4878#[non_exhaustive]
4879pub struct ExploreMarketFreshness {
4880    pub enrichment_status: EnrichmentStatus,
4881    pub price_status: EnrichmentStatus,
4882}
4883
4884#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4885#[non_exhaustive]
4886pub struct ExploreMarketScoreComponents {
4887    #[serde(default)]
4888    pub volume_signal: Option<f64>,
4889    /// 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).
4890    #[serde(default)]
4891    pub large_trade_signal: Option<f64>,
4892    /// 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.
4893    #[serde(default)]
4894    pub whale_signal: Option<f64>,
4895    #[serde(default)]
4896    pub liquidity_signal: Option<f64>,
4897    #[serde(default)]
4898    pub recency_signal: Option<f64>,
4899    /// 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).
4900    #[serde(default)]
4901    pub sharp_money_signal: Option<f64>,
4902    /// 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.
4903    #[serde(default)]
4904    pub smart_money_signal: Option<f64>,
4905    #[serde(default)]
4906    pub price_move_signal: Option<f64>,
4907    pub missing_price_penalty: f64,
4908}
4909
4910#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4911#[non_exhaustive]
4912pub struct ExploreMarketsResponse {
4913    pub object: String,
4914    pub data: Vec<ExploreEntry>,
4915    pub has_more: bool,
4916    #[serde(default, skip_serializing_if = "Option::is_none")]
4917    pub next_cursor: Option<String>,
4918    /// Total matching visible entries after grouping. Present on the first page and omitted on cursor pages.
4919    #[serde(default, skip_serializing_if = "Option::is_none")]
4920    pub total: Option<i64>,
4921    pub facets: ExploreFacets,
4922    pub meta: ResponseMeta,
4923    /// 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.
4924    #[serde(default, skip_serializing_if = "Option::is_none")]
4925    pub computed_at: Option<String>,
4926    /// 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.
4927    #[serde(default, skip_serializing_if = "Option::is_none")]
4928    pub fresh_for_seconds: Option<i64>,
4929}
4930
4931/// A value this release does not know is kept in `Other`, so a new value never fails a response.
4932#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
4933#[non_exhaustive]
4934pub enum ExploreMarketsSort {
4935    /// `trending`
4936    #[serde(rename = "trending")]
4937    Trending,
4938    /// `hot`
4939    #[serde(rename = "hot")]
4940    Hot,
4941    /// `expiring`
4942    #[serde(rename = "expiring")]
4943    Expiring,
4944    /// `large_trades`
4945    #[serde(rename = "large_trades")]
4946    LargeTrades,
4947    /// `whales`
4948    #[serde(rename = "whales")]
4949    Whales,
4950    /// `volume`
4951    #[serde(rename = "volume")]
4952    Volume,
4953    /// `newest`
4954    #[serde(rename = "newest")]
4955    Newest,
4956    /// A value this release does not know, kept as sent.
4957    #[serde(untagged)]
4958    Other(String),
4959}
4960
4961impl ExploreMarketsSort {
4962    /// The value as the API spells it.
4963    pub fn as_str(&self) -> &str {
4964        match self {
4965            Self::Trending => "trending",
4966            Self::Hot => "hot",
4967            Self::Expiring => "expiring",
4968            Self::LargeTrades => "large_trades",
4969            Self::Whales => "whales",
4970            Self::Volume => "volume",
4971            Self::Newest => "newest",
4972            Self::Other(value) => value,
4973        }
4974    }
4975}
4976
4977impl From<&str> for ExploreMarketsSort {
4978    fn from(value: &str) -> Self {
4979        match value {
4980            "trending" => Self::Trending,
4981            "hot" => Self::Hot,
4982            "expiring" => Self::Expiring,
4983            "large_trades" => Self::LargeTrades,
4984            "whales" => Self::Whales,
4985            "volume" => Self::Volume,
4986            "newest" => Self::Newest,
4987            other => Self::Other(other.to_owned()),
4988        }
4989    }
4990}
4991
4992impl std::fmt::Display for ExploreMarketsSort {
4993    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4994        f.write_str(self.as_str())
4995    }
4996}
4997
4998impl AsRef<str> for ExploreMarketsSort {
4999    fn as_ref(&self) -> &str {
5000        self.as_str()
5001    }
5002}
5003
5004#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5005#[non_exhaustive]
5006pub struct ExploreStandalone {
5007    pub r#type: String,
5008    pub market: ExploreMarket,
5009}
5010
5011#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5012#[non_exhaustive]
5013pub struct ExportCompleteness {
5014    pub status: SnapshotCompletenessStatus,
5015    pub reason: String,
5016    pub sync_coverage: f64,
5017}
5018
5019#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5020#[non_exhaustive]
5021pub struct ExportCounts {
5022    /// 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.
5023    pub pnl_days: i64,
5024    /// The wallet's sports and esports markets: the rows of the export's markets section, before its 50,000-row cap.
5025    pub exported_markets: i64,
5026    /// 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.
5027    pub estimated_trade_rows: i64,
5028    /// Estimated file size from estimated_trade_rows and exported_markets.
5029    pub estimated_size_mb: f64,
5030}
5031
5032/// `export_job_cancelled` data: the owner's export stopped because its owner cancelled it.
5033#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5034#[non_exhaustive]
5035pub struct ExportJobCancelledData {
5036    pub job_id: i64,
5037    pub status: String,
5038    pub format: String,
5039    pub next_action: String,
5040}
5041
5042/// `export_job_expired` data: the owner's ready export passed retention.
5043#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5044#[non_exhaustive]
5045pub struct ExportJobExpiredData {
5046    pub job_id: i64,
5047    pub status: String,
5048    pub format: String,
5049    pub next_action: String,
5050}
5051
5052/// `export_job_failed` data: the owner's asynchronous export reached a terminal failure.
5053#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5054#[non_exhaustive]
5055pub struct ExportJobFailedData {
5056    pub job_id: i64,
5057    pub status: String,
5058    pub format: String,
5059    pub next_action: String,
5060    pub failure_reason: String,
5061}
5062
5063/// `export_job_ready` data: the owner's asynchronous export can be downloaded. Download authorization stays on the status and download routes.
5064#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5065#[non_exhaustive]
5066pub struct ExportJobReadyData {
5067    pub job_id: i64,
5068    pub status: String,
5069    pub format: String,
5070    pub next_action: String,
5071    #[serde(default)]
5072    pub total_trades: Option<i64>,
5073    #[serde(default)]
5074    pub processed_trades: Option<i64>,
5075    /// Artifact size in bytes.
5076    #[serde(default)]
5077    pub file_size: Option<i64>,
5078    #[serde(default)]
5079    pub data_as_of: Option<String>,
5080}
5081
5082#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5083#[non_exhaustive]
5084pub struct ExportSourceRange {
5085    /// 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.
5086    #[serde(default)]
5087    pub first_pnl_date: Option<String>,
5088    /// 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.
5089    #[serde(default)]
5090    pub last_pnl_date: Option<String>,
5091    /// 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).
5092    pub pnl_series_status: DailyPnlSeriesStatus,
5093    /// The latest trade in the wallet's sports and esports markets. Null when it has none.
5094    #[serde(default)]
5095    pub latest_trade_at: Option<String>,
5096    /// Same instant as latest_trade_at: the latest activity of the markets the export holds.
5097    #[serde(default)]
5098    pub latest_market_activity_at: Option<String>,
5099}
5100
5101#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5102#[non_exhaustive]
5103pub struct ExportVolumeReconciliation {
5104    /// 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.
5105    #[serde(default)]
5106    pub provider_lifetime_volume: Option<f64>,
5107    /// 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.
5108    #[serde(default)]
5109    pub exported_activity_volume: Option<f64>,
5110    /// Cost basis in USD summed over the wallet's sports and esports markets, the markets section of the export.
5111    pub exported_market_cost_basis: f64,
5112    /// 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.
5113    #[serde(default)]
5114    pub provider_activity_volume_gap: Option<f64>,
5115    /// Always null, for the same reason as provider_activity_volume_gap.
5116    #[serde(default)]
5117    pub activity_volume_coverage: Option<f64>,
5118}
5119
5120/// A value this release does not know is kept in `Other`, so a new value never fails a response.
5121#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
5122#[non_exhaustive]
5123pub enum Format {
5124    /// `json`
5125    #[serde(rename = "json")]
5126    Json,
5127    /// `ndjson`
5128    #[serde(rename = "ndjson")]
5129    Ndjson,
5130    /// `csv`
5131    #[serde(rename = "csv")]
5132    Csv,
5133    /// A value this release does not know, kept as sent.
5134    #[serde(untagged)]
5135    Other(String),
5136}
5137
5138impl Format {
5139    /// The value as the API spells it.
5140    pub fn as_str(&self) -> &str {
5141        match self {
5142            Self::Json => "json",
5143            Self::Ndjson => "ndjson",
5144            Self::Csv => "csv",
5145            Self::Other(value) => value,
5146        }
5147    }
5148}
5149
5150impl From<&str> for Format {
5151    fn from(value: &str) -> Self {
5152        match value {
5153            "json" => Self::Json,
5154            "ndjson" => Self::Ndjson,
5155            "csv" => Self::Csv,
5156            other => Self::Other(other.to_owned()),
5157        }
5158    }
5159}
5160
5161impl std::fmt::Display for Format {
5162    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5163        f.write_str(self.as_str())
5164    }
5165}
5166
5167impl AsRef<str> for Format {
5168    fn as_ref(&self) -> &str {
5169        self.as_str()
5170    }
5171}
5172
5173/// A value this release does not know is kept in `Other`, so a new value never fails a response.
5174#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
5175#[non_exhaustive]
5176pub enum Freshness {
5177    /// `fresh`
5178    #[serde(rename = "fresh")]
5179    Fresh,
5180    /// `refreshing`
5181    #[serde(rename = "refreshing")]
5182    Refreshing,
5183    /// `stale`
5184    #[serde(rename = "stale")]
5185    Stale,
5186    /// `unknown`
5187    #[serde(rename = "unknown")]
5188    Unknown,
5189    /// A value this release does not know, kept as sent.
5190    #[serde(untagged)]
5191    Other(String),
5192}
5193
5194impl Freshness {
5195    /// The value as the API spells it.
5196    pub fn as_str(&self) -> &str {
5197        match self {
5198            Self::Fresh => "fresh",
5199            Self::Refreshing => "refreshing",
5200            Self::Stale => "stale",
5201            Self::Unknown => "unknown",
5202            Self::Other(value) => value,
5203        }
5204    }
5205}
5206
5207impl From<&str> for Freshness {
5208    fn from(value: &str) -> Self {
5209        match value {
5210            "fresh" => Self::Fresh,
5211            "refreshing" => Self::Refreshing,
5212            "stale" => Self::Stale,
5213            "unknown" => Self::Unknown,
5214            other => Self::Other(other.to_owned()),
5215        }
5216    }
5217}
5218
5219impl std::fmt::Display for Freshness {
5220    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5221        f.write_str(self.as_str())
5222    }
5223}
5224
5225impl AsRef<str> for Freshness {
5226    fn as_ref(&self) -> &str {
5227        self.as_str()
5228    }
5229}
5230
5231#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5232#[non_exhaustive]
5233pub struct FreshnessFailure {
5234    /// The caller's requested whole-response freshness ceiling in seconds.
5235    pub max_age_s: i64,
5236    /// Age in seconds of the oldest stored data_quality.as_of clock, when one is available.
5237    #[serde(default, skip_serializing_if = "Option::is_none")]
5238    pub actual_age_s: Option<i64>,
5239    /// The oldest stored data-quality clock used to calculate actual_age_s, when one is available.
5240    #[serde(default, skip_serializing_if = "Option::is_none")]
5241    pub as_of: Option<String>,
5242    /// 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.
5243    pub data_quality_status: DataQualityGroupStatus,
5244}
5245
5246/// 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.
5247#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5248#[non_exhaustive]
5249pub struct Game {
5250    pub object: String,
5251    /// 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.
5252    pub event_slug: String,
5253    /// 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.
5254    #[serde(default, skip_serializing_if = "Option::is_none")]
5255    pub game_id: Option<String>,
5256    /// The canonical sport bucket, for example Soccer or Table Tennis. Omitted when neither the board scope nor the provider category names one.
5257    #[serde(default, skip_serializing_if = "Option::is_none")]
5258    pub sport: Option<String>,
5259    /// The league tag, for example nfl or epl. Omitted for a sport served as one whole bucket with no league scope.
5260    #[serde(default, skip_serializing_if = "Option::is_none")]
5261    pub league: Option<String>,
5262    /// The provider's event title. Omitted when the provider sent none.
5263    #[serde(default, skip_serializing_if = "Option::is_none")]
5264    pub title: Option<String>,
5265    /// Kickoff in UTC, as the provider supplied it. Omitted when the provider published none; coverage.schedule then reads unavailable.
5266    #[serde(default, skip_serializing_if = "Option::is_none")]
5267    pub scheduled_at: Option<String>,
5268    pub status: GameStatus,
5269    /// Both sides, in the provider's own order. For a team league the provider lists the home side first. Empty when the provider identified neither side.
5270    pub competitors: Vec<GameCompetitor>,
5271    /// The esports series length, for example Bo3. Omitted for everything else.
5272    #[serde(default, skip_serializing_if = "Option::is_none")]
5273    pub series_format: Option<String>,
5274    /// 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.
5275    pub draw_offered: bool,
5276    /// 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.
5277    pub markets: Vec<GameMarket>,
5278    pub freshness: GameFreshness,
5279    pub coverage: GameCoverage,
5280    /// The game's page on 0xinsider.
5281    pub url: String,
5282    #[serde(default, skip_serializing_if = "Option::is_none")]
5283    pub sharp_money: Option<GameSharpMoney>,
5284    /// 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.
5285    #[serde(default, skip_serializing_if = "Option::is_none")]
5286    pub volume: Option<GameVolume>,
5287    /// 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.
5288    #[serde(default, skip_serializing_if = "Option::is_none")]
5289    pub tournament: Option<GameTournament>,
5290}
5291
5292/// One side of the game.
5293#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5294#[non_exhaustive]
5295pub struct GameCompetitor {
5296    /// The competitor's name as the provider gives it.
5297    pub name: String,
5298    /// The provider's league-scoped competitor id, as a string. Omitted when the provider has not identified this side; coverage.competitors then reads labels.
5299    #[serde(default, skip_serializing_if = "Option::is_none")]
5300    pub provider_id: Option<String>,
5301    /// Provider crest or logo URL. Omitted when there is none.
5302    #[serde(default, skip_serializing_if = "Option::is_none")]
5303    pub logo: Option<String>,
5304    /// 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.
5305    #[serde(default, skip_serializing_if = "Option::is_none")]
5306    pub score: Option<String>,
5307    /// The provider's season record for this side, for example 12-4. Omitted when the provider sent none.
5308    #[serde(default, skip_serializing_if = "Option::is_none")]
5309    pub record: Option<String>,
5310}
5311
5312/// What this game's read actually supplied, so a client branches on coverage instead of on a missing key.
5313#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5314#[non_exhaustive]
5315pub struct GameCoverage {
5316    /// 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.
5317    pub scores: EnrichmentStatus,
5318    /// 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.
5319    pub competitors: Competitors,
5320    /// available when the provider supplied a kickoff.
5321    pub schedule: EnrichmentStatus,
5322}
5323
5324/// 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.
5325#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5326#[non_exhaustive]
5327pub struct GameFreshness {
5328    /// 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).
5329    pub source: GameFreshnessSource,
5330    /// Whether that half returned a truthful source body for this read.
5331    pub source_status: SourceStatus,
5332    /// Whether that half had a source body at all. not_applicable means the sport has no configured source for that half.
5333    pub source_availability: SourceAvailability,
5334    /// 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.
5335    pub source_freshness: SourceFreshness,
5336    /// 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.
5337    #[serde(default, skip_serializing_if = "Option::is_none")]
5338    pub source_observed_at: Option<String>,
5339    /// Age of source_observed_at in seconds, capped at 600. Omitted past the cap or with no anchor.
5340    #[serde(default, skip_serializing_if = "Option::is_none")]
5341    pub source_age_seconds: Option<i64>,
5342    /// 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.
5343    pub delayed: bool,
5344    /// When this game's live-score frame was observed. Omitted when there is no frame.
5345    #[serde(default, skip_serializing_if = "Option::is_none")]
5346    pub scores_observed_at: Option<String>,
5347    /// The provider's own frame clock. Omitted when the frame carries none.
5348    #[serde(default, skip_serializing_if = "Option::is_none")]
5349    pub scores_source_at: Option<String>,
5350}
5351
5352/// A value this release does not know is kept in `Other`, so a new value never fails a response.
5353#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
5354#[non_exhaustive]
5355pub enum GameFreshnessSource {
5356    /// `live`
5357    #[serde(rename = "live")]
5358    Live,
5359    /// `upcoming`
5360    #[serde(rename = "upcoming")]
5361    Upcoming,
5362    /// `stored`
5363    #[serde(rename = "stored")]
5364    Stored,
5365    /// A value this release does not know, kept as sent.
5366    #[serde(untagged)]
5367    Other(String),
5368}
5369
5370impl GameFreshnessSource {
5371    /// The value as the API spells it.
5372    pub fn as_str(&self) -> &str {
5373        match self {
5374            Self::Live => "live",
5375            Self::Upcoming => "upcoming",
5376            Self::Stored => "stored",
5377            Self::Other(value) => value,
5378        }
5379    }
5380}
5381
5382impl From<&str> for GameFreshnessSource {
5383    fn from(value: &str) -> Self {
5384        match value {
5385            "live" => Self::Live,
5386            "upcoming" => Self::Upcoming,
5387            "stored" => Self::Stored,
5388            other => Self::Other(other.to_owned()),
5389        }
5390    }
5391}
5392
5393impl std::fmt::Display for GameFreshnessSource {
5394    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5395        f.write_str(self.as_str())
5396    }
5397}
5398
5399impl AsRef<str> for GameFreshnessSource {
5400    fn as_ref(&self) -> &str {
5401        self.as_str()
5402    }
5403}
5404
5405/// One market of a game holders batch: GET /api/v1/market/{condition_id}/holders unfiltered and cut to the batch limit.
5406#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5407#[non_exhaustive]
5408pub struct GameHoldersItem {
5409    /// The roster's top holders by current value, at most limit.
5410    pub data: Vec<MarketHolder>,
5411    /// More graded holders than limit: page them on GET /api/v1/market/{condition_id}/holders.
5412    pub has_more: bool,
5413    /// Graded holders in the roster, across every page.
5414    pub total: i64,
5415    pub market: MarketHoldersMarket,
5416    pub scan: MarketHoldersScan,
5417    pub totals: MarketHoldersTotals,
5418    /// When this roster was computed. A cached roster is at most 60 seconds old.
5419    pub computed_at: String,
5420    /// true when the roster came from the 60-second roster cache.
5421    pub cached: bool,
5422}
5423
5424/// One Polymarket market linked to this game.
5425#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5426#[non_exhaustive]
5427pub struct GameMarket {
5428    /// The mkt_-prefixed market id every other V1 response uses.
5429    pub id: String,
5430    /// The raw provider condition id.
5431    pub condition_id: String,
5432    /// Always polymarket.
5433    pub platform: String,
5434    /// The provider's market slug. Omitted when the provider sent none.
5435    #[serde(default, skip_serializing_if = "Option::is_none")]
5436    pub slug: Option<String>,
5437    /// 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.
5438    #[serde(default, skip_serializing_if = "Option::is_none")]
5439    pub sports_market_type: Option<String>,
5440    /// Which side of the game this market's YES leg pays. 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, which is not the same as other.
5441    #[serde(default, skip_serializing_if = "Option::is_none")]
5442    pub side: Option<GameMarketSide>,
5443    /// The provider's label for the YES outcome. Omitted when the provider sent none.
5444    #[serde(default, skip_serializing_if = "Option::is_none")]
5445    pub outcome_yes: Option<String>,
5446    /// The provider's label for the NO outcome. Omitted when the provider sent none.
5447    #[serde(default, skip_serializing_if = "Option::is_none")]
5448    pub outcome_no: Option<String>,
5449    /// Polymarket CLOB token ids in the provider's own outcome-index order. Omitted when the provider has published none for this market.
5450    #[serde(default, skip_serializing_if = "Option::is_none")]
5451    pub outcome_token_ids: Option<Vec<String>>,
5452    /// Default provider moneyline state. Omitted when this market has no classified moneyline projection; incomplete and invalid projections remain explicit.
5453    #[serde(default, skip_serializing_if = "Option::is_none")]
5454    pub prices: Option<GameMarketPrices>,
5455    /// 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.
5456    #[serde(default, skip_serializing_if = "Option::is_none")]
5457    pub liquidity: Option<GameMarketLiquidity>,
5458}
5459
5460/// 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.
5461#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5462#[non_exhaustive]
5463pub struct GameMarketLiquidity {
5464    /// The provider's figure at full precision.
5465    pub value: f64,
5466    /// Always gamma: the Polymarket Gamma API.
5467    pub source: String,
5468    /// When 0xinsider read the sports board body this figure came from, never a provider-authored timestamp. Omitted when that read has no clock.
5469    #[serde(default, skip_serializing_if = "Option::is_none")]
5470    pub observed_at: Option<String>,
5471}
5472
5473/// How the existing sports-board writer bound prices to competitors.
5474///
5475/// A value this release does not know is kept in `Other`, so a new value never fails a response.
5476#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
5477#[non_exhaustive]
5478pub enum GameMarketPriceBindingProvenance {
5479    /// `provider_ids`
5480    #[serde(rename = "provider_ids")]
5481    ProviderIds,
5482    /// `exact_labels`
5483    #[serde(rename = "exact_labels")]
5484    ExactLabels,
5485    /// `containment_labels`
5486    #[serde(rename = "containment_labels")]
5487    ContainmentLabels,
5488    /// `elimination`
5489    #[serde(rename = "elimination")]
5490    Elimination,
5491    /// A value this release does not know, kept as sent.
5492    #[serde(untagged)]
5493    Other(String),
5494}
5495
5496impl GameMarketPriceBindingProvenance {
5497    /// The value as the API spells it.
5498    pub fn as_str(&self) -> &str {
5499        match self {
5500            Self::ProviderIds => "provider_ids",
5501            Self::ExactLabels => "exact_labels",
5502            Self::ContainmentLabels => "containment_labels",
5503            Self::Elimination => "elimination",
5504            Self::Other(value) => value,
5505        }
5506    }
5507}
5508
5509impl From<&str> for GameMarketPriceBindingProvenance {
5510    fn from(value: &str) -> Self {
5511        match value {
5512            "provider_ids" => Self::ProviderIds,
5513            "exact_labels" => Self::ExactLabels,
5514            "containment_labels" => Self::ContainmentLabels,
5515            "elimination" => Self::Elimination,
5516            other => Self::Other(other.to_owned()),
5517        }
5518    }
5519}
5520
5521impl std::fmt::Display for GameMarketPriceBindingProvenance {
5522    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5523        f.write_str(self.as_str())
5524    }
5525}
5526
5527impl AsRef<str> for GameMarketPriceBindingProvenance {
5528    fn as_ref(&self) -> &str {
5529        self.as_str()
5530    }
5531}
5532
5533/// One competitor-bound provider moneyline price. No YES/NO inference is required.
5534#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5535#[non_exhaustive]
5536pub struct GameMarketPriceCompetitor {
5537    /// The provider competitor id when identity is available.
5538    #[serde(default, skip_serializing_if = "Option::is_none")]
5539    pub provider_id: Option<i64>,
5540    /// The provider competitor label.
5541    pub label: String,
5542    /// Unrounded provider price in [0, 1].
5543    pub price: f64,
5544    /// Which provider price observation supplies this leg.
5545    pub price_provenance: PriceProvenance,
5546}
5547
5548/// The provider moneyline pair is incomplete; no numeric pair is invented.
5549#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5550#[non_exhaustive]
5551pub struct GameMarketPriceIncomplete {
5552    pub state: String,
5553    pub reason: Reason,
5554    /// Whether competitor A is the provider YES leg.
5555    #[serde(default, skip_serializing_if = "Option::is_none")]
5556    pub competitor_a_is_yes: Option<bool>,
5557    /// The provider competitor id when identity is available.
5558    #[serde(default, skip_serializing_if = "Option::is_none")]
5559    pub competitor_a_provider_id: Option<i64>,
5560    /// The provider competitor id when identity is available.
5561    #[serde(default, skip_serializing_if = "Option::is_none")]
5562    pub competitor_b_provider_id: Option<i64>,
5563    #[serde(default, skip_serializing_if = "Option::is_none")]
5564    pub binding_provenance: Option<GameMarketPriceBindingProvenance>,
5565}
5566
5567/// The provider moneyline pair is invalid; no numeric pair is invented.
5568#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5569#[non_exhaustive]
5570pub struct GameMarketPriceInvalid {
5571    pub state: String,
5572    pub reason: GameMarketPriceInvalidReason,
5573    /// Whether competitor A is the provider YES leg.
5574    #[serde(default, skip_serializing_if = "Option::is_none")]
5575    pub competitor_a_is_yes: Option<bool>,
5576    /// The provider competitor id when identity is available.
5577    #[serde(default, skip_serializing_if = "Option::is_none")]
5578    pub competitor_a_provider_id: Option<i64>,
5579    /// The provider competitor id when identity is available.
5580    #[serde(default, skip_serializing_if = "Option::is_none")]
5581    pub competitor_b_provider_id: Option<i64>,
5582    #[serde(default, skip_serializing_if = "Option::is_none")]
5583    pub binding_provenance: Option<GameMarketPriceBindingProvenance>,
5584}
5585
5586/// A value this release does not know is kept in `Other`, so a new value never fails a response.
5587#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
5588#[non_exhaustive]
5589pub enum GameMarketPriceInvalidReason {
5590    /// `team_cardinality`
5591    #[serde(rename = "team_cardinality")]
5592    TeamCardinality,
5593    /// `outcome_cardinality`
5594    #[serde(rename = "outcome_cardinality")]
5595    OutcomeCardinality,
5596    /// `price_cardinality`
5597    #[serde(rename = "price_cardinality")]
5598    PriceCardinality,
5599    /// `non_finite_price`
5600    #[serde(rename = "non_finite_price")]
5601    NonFinitePrice,
5602    /// `out_of_range_price`
5603    #[serde(rename = "out_of_range_price")]
5604    OutOfRangePrice,
5605    /// `non_complementary_prices`
5606    #[serde(rename = "non_complementary_prices")]
5607    NonComplementaryPrices,
5608    /// `ambiguous_identity`
5609    #[serde(rename = "ambiguous_identity")]
5610    AmbiguousIdentity,
5611    /// `final_identity_mismatch`
5612    #[serde(rename = "final_identity_mismatch")]
5613    FinalIdentityMismatch,
5614    /// A value this release does not know, kept as sent.
5615    #[serde(untagged)]
5616    Other(String),
5617}
5618
5619impl GameMarketPriceInvalidReason {
5620    /// The value as the API spells it.
5621    pub fn as_str(&self) -> &str {
5622        match self {
5623            Self::TeamCardinality => "team_cardinality",
5624            Self::OutcomeCardinality => "outcome_cardinality",
5625            Self::PriceCardinality => "price_cardinality",
5626            Self::NonFinitePrice => "non_finite_price",
5627            Self::OutOfRangePrice => "out_of_range_price",
5628            Self::NonComplementaryPrices => "non_complementary_prices",
5629            Self::AmbiguousIdentity => "ambiguous_identity",
5630            Self::FinalIdentityMismatch => "final_identity_mismatch",
5631            Self::Other(value) => value,
5632        }
5633    }
5634}
5635
5636impl From<&str> for GameMarketPriceInvalidReason {
5637    fn from(value: &str) -> Self {
5638        match value {
5639            "team_cardinality" => Self::TeamCardinality,
5640            "outcome_cardinality" => Self::OutcomeCardinality,
5641            "price_cardinality" => Self::PriceCardinality,
5642            "non_finite_price" => Self::NonFinitePrice,
5643            "out_of_range_price" => Self::OutOfRangePrice,
5644            "non_complementary_prices" => Self::NonComplementaryPrices,
5645            "ambiguous_identity" => Self::AmbiguousIdentity,
5646            "final_identity_mismatch" => Self::FinalIdentityMismatch,
5647            other => Self::Other(other.to_owned()),
5648        }
5649    }
5650}
5651
5652impl std::fmt::Display for GameMarketPriceInvalidReason {
5653    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5654        f.write_str(self.as_str())
5655    }
5656}
5657
5658impl AsRef<str> for GameMarketPriceInvalidReason {
5659    fn as_ref(&self) -> &str {
5660        self.as_str()
5661    }
5662}
5663
5664/// A validated provider moneyline pair bound to the two competitors.
5665#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5666#[non_exhaustive]
5667pub struct GameMarketPricePaired {
5668    pub state: String,
5669    pub competitor_a: GameMarketPriceCompetitor,
5670    pub competitor_b: GameMarketPriceCompetitor,
5671    /// Whether competitor A is the provider YES leg.
5672    pub competitor_a_is_yes: bool,
5673    pub binding_provenance: GameMarketPriceBindingProvenance,
5674}
5675
5676/// Provider-owned moneyline state with the observation clock that can be compared with game freshness.
5677#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5678#[non_exhaustive]
5679pub struct GameMarketPrices {
5680    pub provider: GameMarketProviderPrices,
5681    /// Board cache vintage for Gamma or the older CLOB leg clock. Null when no reliable clock is available; never a Gamma-authored timestamp.
5682    #[serde(default)]
5683    pub observed_at: Option<String>,
5684    /// The clock used for observed_at. board_snapshot is this service’s cache observation, not a provider source timestamp.
5685    pub observation_source: ObservationSource,
5686}
5687
5688/// Discriminated by `state`. A `state` this release does not know is kept whole in
5689/// `Unknown`, so a new kind never fails a response.
5690#[derive(Debug, Clone, PartialEq)]
5691#[non_exhaustive]
5692pub enum GameMarketProviderPrices {
5693    /// `state` is `paired`.
5694    Paired(GameMarketPricePaired),
5695    /// `state` is `incomplete`.
5696    Incomplete(GameMarketPriceIncomplete),
5697    /// `state` is `invalid`.
5698    Invalid(GameMarketPriceInvalid),
5699    /// A `state` this release does not know, kept as sent.
5700    Unknown(serde_json::Value),
5701}
5702
5703impl<'de> Deserialize<'de> for GameMarketProviderPrices {
5704    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
5705        let value = serde_json::Value::deserialize(deserializer)?;
5706        match value.get("state").and_then(serde_json::Value::as_str) {
5707            Some("paired") => serde_json::from_value(value)
5708                .map(Self::Paired)
5709                .map_err(de::Error::custom),
5710            Some("incomplete") => serde_json::from_value(value)
5711                .map(Self::Incomplete)
5712                .map_err(de::Error::custom),
5713            Some("invalid") => serde_json::from_value(value)
5714                .map(Self::Invalid)
5715                .map_err(de::Error::custom),
5716            _ => Ok(Self::Unknown(value)),
5717        }
5718    }
5719}
5720
5721impl Serialize for GameMarketProviderPrices {
5722    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
5723        match self {
5724            Self::Paired(inner) => inner.serialize(serializer),
5725            Self::Incomplete(inner) => inner.serialize(serializer),
5726            Self::Invalid(inner) => inner.serialize(serializer),
5727            Self::Unknown(inner) => inner.serialize(serializer),
5728        }
5729    }
5730}
5731
5732/// A value this release does not know is kept in `Other`, so a new value never fails a response.
5733#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
5734#[non_exhaustive]
5735pub enum GameMarketSide {
5736    /// `home`
5737    #[serde(rename = "home")]
5738    Home,
5739    /// `away`
5740    #[serde(rename = "away")]
5741    Away,
5742    /// `draw`
5743    #[serde(rename = "draw")]
5744    Draw,
5745    /// `other`, the documented value; `Other` holds values this release does not know.
5746    #[serde(rename = "other")]
5747    OtherValue,
5748    /// A value this release does not know, kept as sent.
5749    #[serde(untagged)]
5750    Other(String),
5751}
5752
5753impl GameMarketSide {
5754    /// The value as the API spells it.
5755    pub fn as_str(&self) -> &str {
5756        match self {
5757            Self::Home => "home",
5758            Self::Away => "away",
5759            Self::Draw => "draw",
5760            Self::OtherValue => "other",
5761            Self::Other(value) => value,
5762        }
5763    }
5764}
5765
5766impl From<&str> for GameMarketSide {
5767    fn from(value: &str) -> Self {
5768        match value {
5769            "home" => Self::Home,
5770            "away" => Self::Away,
5771            "draw" => Self::Draw,
5772            "other" => Self::OtherValue,
5773            other => Self::Other(other.to_owned()),
5774        }
5775    }
5776}
5777
5778impl std::fmt::Display for GameMarketSide {
5779    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5780        f.write_str(self.as_str())
5781    }
5782}
5783
5784impl AsRef<str> for GameMarketSide {
5785    fn as_ref(&self) -> &str {
5786        self.as_str()
5787    }
5788}
5789
5790/// Event-level sharp money for one game. Every aggregate field is null unless status is computed; null means unknown, never zero.
5791#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5792#[non_exhaustive]
5793pub struct GameSharpMoney {
5794    #[serde(default)]
5795    pub allocation: Option<Allocation>,
5796    #[serde(default)]
5797    pub computed_at: Option<String>,
5798    pub event_slug: String,
5799    #[serde(default)]
5800    pub holders_partial: Option<bool>,
5801    #[serde(default)]
5802    pub lifecycle: Option<Lifecycle>,
5803    #[serde(default)]
5804    pub money_as_of: Option<String>,
5805    pub object: String,
5806    pub outcomes: Vec<GameSharpMoneyOutcomesItem>,
5807    pub status: GameSharpMoneyStatus,
5808    #[serde(default)]
5809    pub total_usd: Option<f64>,
5810    #[serde(default)]
5811    pub trader_count: Option<i64>,
5812    #[serde(default)]
5813    pub unallocated_usd: Option<f64>,
5814    #[serde(default)]
5815    pub verdict: Option<serde_json::Value>,
5816}
5817
5818#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5819#[non_exhaustive]
5820pub struct GameSharpMoneyOutcomesItem {
5821    pub is_leader: bool,
5822    pub label: String,
5823    pub pct: i64,
5824    pub side: GameSharpMoneyOutcomesSide,
5825    pub usd: f64,
5826    pub wallets: GameSharpMoneyOutcomesItemWallets,
5827}
5828
5829#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5830#[non_exhaustive]
5831pub struct GameSharpMoneyOutcomesItemWallets {
5832    pub a: i64,
5833    pub b: i64,
5834    pub s: i64,
5835}
5836
5837/// A value this release does not know is kept in `Other`, so a new value never fails a response.
5838#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
5839#[non_exhaustive]
5840pub enum GameSharpMoneyOutcomesSide {
5841    /// `home`
5842    #[serde(rename = "home")]
5843    Home,
5844    /// `draw`
5845    #[serde(rename = "draw")]
5846    Draw,
5847    /// `away`
5848    #[serde(rename = "away")]
5849    Away,
5850    /// A value this release does not know, kept as sent.
5851    #[serde(untagged)]
5852    Other(String),
5853}
5854
5855impl GameSharpMoneyOutcomesSide {
5856    /// The value as the API spells it.
5857    pub fn as_str(&self) -> &str {
5858        match self {
5859            Self::Home => "home",
5860            Self::Draw => "draw",
5861            Self::Away => "away",
5862            Self::Other(value) => value,
5863        }
5864    }
5865}
5866
5867impl From<&str> for GameSharpMoneyOutcomesSide {
5868    fn from(value: &str) -> Self {
5869        match value {
5870            "home" => Self::Home,
5871            "draw" => Self::Draw,
5872            "away" => Self::Away,
5873            other => Self::Other(other.to_owned()),
5874        }
5875    }
5876}
5877
5878impl std::fmt::Display for GameSharpMoneyOutcomesSide {
5879    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5880        f.write_str(self.as_str())
5881    }
5882}
5883
5884impl AsRef<str> for GameSharpMoneyOutcomesSide {
5885    fn as_ref(&self) -> &str {
5886        self.as_str()
5887    }
5888}
5889
5890/// A value this release does not know is kept in `Other`, so a new value never fails a response.
5891#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
5892#[non_exhaustive]
5893pub enum GameSharpMoneyStatus {
5894    /// `computed`
5895    #[serde(rename = "computed")]
5896    Computed,
5897    /// `not_computed`
5898    #[serde(rename = "not_computed")]
5899    NotComputed,
5900    /// `unavailable`
5901    #[serde(rename = "unavailable")]
5902    Unavailable,
5903    /// A value this release does not know, kept as sent.
5904    #[serde(untagged)]
5905    Other(String),
5906}
5907
5908impl GameSharpMoneyStatus {
5909    /// The value as the API spells it.
5910    pub fn as_str(&self) -> &str {
5911        match self {
5912            Self::Computed => "computed",
5913            Self::NotComputed => "not_computed",
5914            Self::Unavailable => "unavailable",
5915            Self::Other(value) => value,
5916        }
5917    }
5918}
5919
5920impl From<&str> for GameSharpMoneyStatus {
5921    fn from(value: &str) -> Self {
5922        match value {
5923            "computed" => Self::Computed,
5924            "not_computed" => Self::NotComputed,
5925            "unavailable" => Self::Unavailable,
5926            other => Self::Other(other.to_owned()),
5927        }
5928    }
5929}
5930
5931impl std::fmt::Display for GameSharpMoneyStatus {
5932    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5933        f.write_str(self.as_str())
5934    }
5935}
5936
5937impl AsRef<str> for GameSharpMoneyStatus {
5938    fn as_ref(&self) -> &str {
5939        self.as_str()
5940    }
5941}
5942
5943/// 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.
5944#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5945#[non_exhaustive]
5946pub struct GameStatus {
5947    /// 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.
5948    pub state: State,
5949    /// 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.
5950    #[serde(default, skip_serializing_if = "Option::is_none")]
5951    pub match_status: Option<MatchStatus>,
5952    /// 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.
5953    #[serde(default, skip_serializing_if = "Option::is_none")]
5954    pub provider_status: Option<String>,
5955    /// The provider's period label, for example Q3, End Q2 or T5. Omitted when the provider sent none.
5956    #[serde(default, skip_serializing_if = "Option::is_none")]
5957    pub period: Option<String>,
5958    /// The game clock as the provider spells it, never reformatted. Omitted when the provider sent none.
5959    #[serde(default, skip_serializing_if = "Option::is_none")]
5960    pub clock: Option<String>,
5961    /// 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.
5962    #[serde(default, skip_serializing_if = "Option::is_none")]
5963    pub live: Option<bool>,
5964    /// Whether the game is over. Always present.
5965    pub ended: bool,
5966}
5967
5968/// 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.
5969#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5970#[non_exhaustive]
5971pub struct GameTournament {
5972    /// The provider competition label that selected this edition, verbatim, for example "Erste Bank Open, Qualification".
5973    pub label: String,
5974    /// The edition's tour.
5975    pub tour: Tour,
5976    /// 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.
5977    #[serde(default, skip_serializing_if = "Option::is_none")]
5978    pub draw: Option<Draw>,
5979    /// 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.
5980    #[serde(default, skip_serializing_if = "Option::is_none")]
5981    pub tier: Option<String>,
5982    /// The verified venue city and country. Omitted when no official page states it.
5983    #[serde(default, skip_serializing_if = "Option::is_none")]
5984    pub location: Option<GameTournamentLocation>,
5985    /// 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.
5986    #[serde(default, skip_serializing_if = "Option::is_none")]
5987    pub timezone: Option<String>,
5988    /// The year of the edition.
5989    pub edition_year: i64,
5990    /// The edition's first official day, inclusive (YYYY-MM-DD). A qualifying match can be played up to two days before it.
5991    pub starts_on: String,
5992    /// The edition's last official day, inclusive (YYYY-MM-DD).
5993    pub ends_on: String,
5994    /// The official tournament, tour, federation or time-zone pages the facts were taken from.
5995    pub source_urls: Vec<String>,
5996    /// When those pages were checked: a catalogue verification date, not a score or price clock.
5997    pub checked_on: String,
5998}
5999
6000/// A verified tournament venue.
6001#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6002#[non_exhaustive]
6003pub struct GameTournamentLocation {
6004    pub city: String,
6005    pub country: String,
6006    /// ISO 3166-1 alpha-2, for example "IT".
6007    pub country_code: String,
6008}
6009
6010/// One fill in a game, as the game page's activity list shows it.
6011#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6012#[non_exhaustive]
6013pub struct GameTrade {
6014    /// Stable fill identity: {transaction_hash}:{token_id}:{wallet}:{shares}. Deduplicate on it across polls.
6015    pub id: String,
6016    /// When the fill happened, to the second.
6017    pub traded_at: String,
6018    /// The provider's side of the fill.
6019    pub side: Side,
6020    /// The traded outcome's label; null when the provider named none.
6021    #[serde(default)]
6022    pub outcome: Option<String>,
6023    /// 0 for the first (Yes) outcome token, 1 for the second (No); null when the provider did not say.
6024    #[serde(default)]
6025    pub outcome_index: Option<i64>,
6026    /// Fill price, 0 to 1.
6027    pub price: f64,
6028    /// Shares filled.
6029    pub shares: f64,
6030    /// USDC notional of the fill.
6031    pub size_usd: f64,
6032    /// The signed handicap the fill's side carries on a spread line, for example -1.5 or 1.5; null off spreads.
6033    #[serde(default)]
6034    pub point: Option<f64>,
6035    pub trader: GameTradeTrader,
6036    pub market: GameTradeMarket,
6037}
6038
6039#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6040#[non_exhaustive]
6041pub struct GameTradeMarket {
6042    /// The market's v1 id, mkt_ plus the condition_id.
6043    pub id: String,
6044    /// The raw provider condition_id.
6045    pub condition_id: String,
6046    /// The market's question.
6047    #[serde(default)]
6048    pub title: Option<String>,
6049    /// The market's page slug.
6050    #[serde(default)]
6051    pub slug: Option<String>,
6052    /// 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.
6053    #[serde(default)]
6054    pub line_label: Option<String>,
6055}
6056
6057#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6058#[non_exhaustive]
6059pub struct GameTradeTrader {
6060    /// Lowercase proxy wallet.
6061    pub address: String,
6062    /// The name the site shows: the 0xinsider username, else the provider's name or pseudonym, else the shortened address.
6063    pub display_name: String,
6064    /// The trader's grade today; null for an ungraded or untracked wallet.
6065    #[serde(default)]
6066    pub grade: Option<Grade>,
6067}
6068
6069/// 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.
6070#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6071#[non_exhaustive]
6072pub struct GameVolume {
6073    /// The volume at full precision, in unit.
6074    pub value: f64,
6075    /// 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.
6076    #[serde(default, skip_serializing_if = "Option::is_none")]
6077    pub unit: Option<String>,
6078    /// 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.
6079    #[serde(default, skip_serializing_if = "Option::is_none")]
6080    pub basis: Option<Basis>,
6081    /// The Polymarket API the figure was read from: polymarket_data (the Data API's live volume) or gamma (the Gamma API).
6082    pub source: Source,
6083    /// When 0xinsider read the figure from the provider, never a provider-authored timestamp. Omitted when no read time is held for it.
6084    #[serde(default, skip_serializing_if = "Option::is_none")]
6085    pub observed_at: Option<String>,
6086    /// 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).
6087    pub fresh_for_seconds: i64,
6088}
6089
6090/// 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.
6091#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6092#[non_exhaustive]
6093pub struct GamesCoverage {
6094    /// Canonical sport buckets served, sorted.
6095    pub sports: Vec<String>,
6096    /// 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.
6097    pub leagues: Vec<String>,
6098    /// Scopes whose source half was unavailable for this read, as <sport>:<half>. Empty means every scope answered.
6099    pub sources_unavailable: Vec<String>,
6100}
6101
6102#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6103#[non_exhaustive]
6104pub struct GetApiDiscoveryResponse {
6105    pub object: String,
6106    pub data: ApiDiscovery,
6107    pub meta: ResponseMeta,
6108}
6109
6110#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6111#[non_exhaustive]
6112pub struct GetCategoryLeaderboardResponse {
6113    pub object: String,
6114    pub data: Vec<CategoryLeader>,
6115    pub has_more: bool,
6116    #[serde(default, skip_serializing_if = "Option::is_none")]
6117    pub next_cursor: Option<String>,
6118    /// 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.
6119    #[serde(default, skip_serializing_if = "Option::is_none")]
6120    pub total: Option<i64>,
6121    pub meta: ResponseMeta,
6122}
6123
6124#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6125#[non_exhaustive]
6126pub struct GetCoverageResponse {
6127    pub object: String,
6128    pub data: Platforms,
6129    pub meta: ResponseMeta,
6130}
6131
6132#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6133#[non_exhaustive]
6134pub struct GetDailyReportSnapshotResponse {
6135    pub object: String,
6136    pub data: ReportSnapshot,
6137    pub meta: ResponseMeta,
6138}
6139
6140/// A value this release does not know is kept in `Other`, so a new value never fails a response.
6141#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
6142#[non_exhaustive]
6143pub enum GetEdgeHunterView {
6144    /// `board`
6145    #[serde(rename = "board")]
6146    Board,
6147    /// `signals`
6148    #[serde(rename = "signals")]
6149    Signals,
6150    /// `observations`
6151    #[serde(rename = "observations")]
6152    Observations,
6153    /// A value this release does not know, kept as sent.
6154    #[serde(untagged)]
6155    Other(String),
6156}
6157
6158impl GetEdgeHunterView {
6159    /// The value as the API spells it.
6160    pub fn as_str(&self) -> &str {
6161        match self {
6162            Self::Board => "board",
6163            Self::Signals => "signals",
6164            Self::Observations => "observations",
6165            Self::Other(value) => value,
6166        }
6167    }
6168}
6169
6170impl From<&str> for GetEdgeHunterView {
6171    fn from(value: &str) -> Self {
6172        match value {
6173            "board" => Self::Board,
6174            "signals" => Self::Signals,
6175            "observations" => Self::Observations,
6176            other => Self::Other(other.to_owned()),
6177        }
6178    }
6179}
6180
6181impl std::fmt::Display for GetEdgeHunterView {
6182    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6183        f.write_str(self.as_str())
6184    }
6185}
6186
6187impl AsRef<str> for GetEdgeHunterView {
6188    fn as_ref(&self) -> &str {
6189        self.as_str()
6190    }
6191}
6192
6193/// 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.
6194#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6195#[serde(untagged)]
6196#[non_exhaustive]
6197pub enum GetEventReplaySinceMinSize {
6198    /// A numeric request value.
6199    Number(f64),
6200    /// The exact decimal query spelling, kept unchanged.
6201    Text(String),
6202}
6203impl From<f64> for GetEventReplaySinceMinSize {
6204    fn from(value: f64) -> Self {
6205        Self::Number(value)
6206    }
6207}
6208impl From<String> for GetEventReplaySinceMinSize {
6209    fn from(value: String) -> Self {
6210        Self::Text(value)
6211    }
6212}
6213impl From<&str> for GetEventReplaySinceMinSize {
6214    fn from(value: &str) -> Self {
6215        Self::Text(value.to_owned())
6216    }
6217}
6218impl std::fmt::Display for GetEventReplaySinceMinSize {
6219    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6220        match self {
6221            Self::Number(value) => value.fmt(f),
6222            Self::Text(value) => value.fmt(f),
6223        }
6224    }
6225}
6226
6227#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6228#[non_exhaustive]
6229pub struct GetEventReplaySinceResponse {
6230    pub object: String,
6231    pub data: Vec<EventReplayEvent>,
6232    pub has_more: bool,
6233    pub next_cursor: String,
6234    pub meta: EventReplayMeta,
6235}
6236
6237#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6238#[non_exhaustive]
6239pub struct GetGameHoldersResponse {
6240    pub object: String,
6241    pub data: Vec<BatchGameHoldersItem>,
6242    pub meta: BatchResponseMeta,
6243}
6244
6245#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6246#[non_exhaustive]
6247pub struct GetGameResponse {
6248    pub object: String,
6249    pub data: Game,
6250    /// When this read assembled the catalog. Per-source vintage is on freshness.
6251    pub as_of: String,
6252    pub meta: ResponseMeta,
6253}
6254
6255#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6256#[non_exhaustive]
6257pub struct GetGameSharpMoneyResponse {
6258    pub object: String,
6259    pub data: GameSharpMoney,
6260    pub meta: ResponseMeta,
6261}
6262
6263#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6264#[non_exhaustive]
6265pub struct GetHealthResponse {
6266    pub object: String,
6267    pub data: GetHealthResponseData,
6268    pub meta: ResponseMeta,
6269}
6270
6271#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6272#[non_exhaustive]
6273pub struct GetHealthResponseData {
6274    pub status: GetHealthResponseDataStatus,
6275    pub db: bool,
6276    pub cache: bool,
6277    pub subsystems: GetHealthResponseDataSubsystems,
6278}
6279
6280/// A value this release does not know is kept in `Other`, so a new value never fails a response.
6281#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
6282#[non_exhaustive]
6283pub enum GetHealthResponseDataStatus {
6284    /// `ok`
6285    #[serde(rename = "ok")]
6286    Ok,
6287    /// `degraded`
6288    #[serde(rename = "degraded")]
6289    Degraded,
6290    /// `down`
6291    #[serde(rename = "down")]
6292    Down,
6293    /// `maintenance`
6294    #[serde(rename = "maintenance")]
6295    Maintenance,
6296    /// A value this release does not know, kept as sent.
6297    #[serde(untagged)]
6298    Other(String),
6299}
6300
6301impl GetHealthResponseDataStatus {
6302    /// The value as the API spells it.
6303    pub fn as_str(&self) -> &str {
6304        match self {
6305            Self::Ok => "ok",
6306            Self::Degraded => "degraded",
6307            Self::Down => "down",
6308            Self::Maintenance => "maintenance",
6309            Self::Other(value) => value,
6310        }
6311    }
6312}
6313
6314impl From<&str> for GetHealthResponseDataStatus {
6315    fn from(value: &str) -> Self {
6316        match value {
6317            "ok" => Self::Ok,
6318            "degraded" => Self::Degraded,
6319            "down" => Self::Down,
6320            "maintenance" => Self::Maintenance,
6321            other => Self::Other(other.to_owned()),
6322        }
6323    }
6324}
6325
6326impl std::fmt::Display for GetHealthResponseDataStatus {
6327    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6328        f.write_str(self.as_str())
6329    }
6330}
6331
6332impl AsRef<str> for GetHealthResponseDataStatus {
6333    fn as_ref(&self) -> &str {
6334        self.as_str()
6335    }
6336}
6337
6338#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6339#[non_exhaustive]
6340pub struct GetHealthResponseDataSubsystems {
6341    /// Whether the webhook outbox schema validated on this probe. false lowers status to degraded. true during a maintenance window, when nothing is probed.
6342    pub webhook_compatibility: bool,
6343    /// 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.
6344    pub background_jobs: GetHealthResponseDataSubsystemsBackgroundJobs,
6345}
6346
6347/// 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.
6348#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6349#[non_exhaustive]
6350pub struct GetHealthResponseDataSubsystemsBackgroundJobs {
6351    pub status: GetHealthResponseDataSubsystemsBackgroundJobsStatus,
6352    pub checked: bool,
6353    pub total: i64,
6354    pub healthy: i64,
6355    pub stale: i64,
6356    pub missing: i64,
6357    pub invalid: i64,
6358    pub unconfigured: i64,
6359    /// 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').
6360    pub paused: i64,
6361}
6362
6363/// A value this release does not know is kept in `Other`, so a new value never fails a response.
6364#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
6365#[non_exhaustive]
6366pub enum GetHealthResponseDataSubsystemsBackgroundJobsStatus {
6367    /// `ok`
6368    #[serde(rename = "ok")]
6369    Ok,
6370    /// `degraded`
6371    #[serde(rename = "degraded")]
6372    Degraded,
6373    /// `down`
6374    #[serde(rename = "down")]
6375    Down,
6376    /// `not_checked`
6377    #[serde(rename = "not_checked")]
6378    NotChecked,
6379    /// A value this release does not know, kept as sent.
6380    #[serde(untagged)]
6381    Other(String),
6382}
6383
6384impl GetHealthResponseDataSubsystemsBackgroundJobsStatus {
6385    /// The value as the API spells it.
6386    pub fn as_str(&self) -> &str {
6387        match self {
6388            Self::Ok => "ok",
6389            Self::Degraded => "degraded",
6390            Self::Down => "down",
6391            Self::NotChecked => "not_checked",
6392            Self::Other(value) => value,
6393        }
6394    }
6395}
6396
6397impl From<&str> for GetHealthResponseDataSubsystemsBackgroundJobsStatus {
6398    fn from(value: &str) -> Self {
6399        match value {
6400            "ok" => Self::Ok,
6401            "degraded" => Self::Degraded,
6402            "down" => Self::Down,
6403            "not_checked" => Self::NotChecked,
6404            other => Self::Other(other.to_owned()),
6405        }
6406    }
6407}
6408
6409impl std::fmt::Display for GetHealthResponseDataSubsystemsBackgroundJobsStatus {
6410    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6411        f.write_str(self.as_str())
6412    }
6413}
6414
6415impl AsRef<str> for GetHealthResponseDataSubsystemsBackgroundJobsStatus {
6416    fn as_ref(&self) -> &str {
6417        self.as_str()
6418    }
6419}
6420
6421#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6422#[non_exhaustive]
6423pub struct GetInsiderRadarFlagResponse {
6424    pub object: String,
6425    pub data: SuspiciousTrade,
6426    pub meta: ResponseMeta,
6427}
6428
6429#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6430#[non_exhaustive]
6431pub struct GetLargeTradeResponse {
6432    pub object: String,
6433    pub data: LargeTradeDetail,
6434    pub meta: ResponseMeta,
6435}
6436
6437#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6438#[non_exhaustive]
6439pub struct GetMarketCandlesResponse {
6440    pub object: String,
6441    pub data: MarketCandles,
6442    pub meta: ResponseMeta,
6443}
6444
6445#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6446#[non_exhaustive]
6447pub struct GetMarketFlowResponse {
6448    pub object: String,
6449    pub data: MarketFlow,
6450    pub meta: ResponseMeta,
6451}
6452
6453/// A value this release does not know is kept in `Other`, so a new value never fails a response.
6454#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
6455#[non_exhaustive]
6456pub enum GetMarketHoldersOutcome {
6457    /// `yes`
6458    #[serde(rename = "yes")]
6459    Yes,
6460    /// `no`
6461    #[serde(rename = "no")]
6462    No,
6463    /// `all`
6464    #[serde(rename = "all")]
6465    All,
6466    /// A value this release does not know, kept as sent.
6467    #[serde(untagged)]
6468    Other(String),
6469}
6470
6471impl GetMarketHoldersOutcome {
6472    /// The value as the API spells it.
6473    pub fn as_str(&self) -> &str {
6474        match self {
6475            Self::Yes => "yes",
6476            Self::No => "no",
6477            Self::All => "all",
6478            Self::Other(value) => value,
6479        }
6480    }
6481}
6482
6483impl From<&str> for GetMarketHoldersOutcome {
6484    fn from(value: &str) -> Self {
6485        match value {
6486            "yes" => Self::Yes,
6487            "no" => Self::No,
6488            "all" => Self::All,
6489            other => Self::Other(other.to_owned()),
6490        }
6491    }
6492}
6493
6494impl std::fmt::Display for GetMarketHoldersOutcome {
6495    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6496        f.write_str(self.as_str())
6497    }
6498}
6499
6500impl AsRef<str> for GetMarketHoldersOutcome {
6501    fn as_ref(&self) -> &str {
6502        self.as_str()
6503    }
6504}
6505
6506#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6507#[non_exhaustive]
6508pub struct GetMarketHoldersResponse {
6509    pub object: String,
6510    pub data: Vec<MarketHolder>,
6511    pub has_more: bool,
6512    /// Absent on the last page.
6513    #[serde(default, skip_serializing_if = "Option::is_none")]
6514    pub next_cursor: Option<String>,
6515    /// Holders matching the request's `outcome` and `min_grade` filters across every page.
6516    pub total: i64,
6517    pub market: MarketHoldersMarket,
6518    pub scan: MarketHoldersScan,
6519    pub totals: MarketHoldersTotals,
6520    pub meta: ResponseMeta,
6521}
6522
6523#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6524#[non_exhaustive]
6525pub struct GetMarketIntelResponse {
6526    pub object: String,
6527    pub data: MarketFlow,
6528    pub meta: ResponseMeta,
6529}
6530
6531#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6532#[non_exhaustive]
6533pub struct GetMarketSnapshotResponse {
6534    pub object: String,
6535    pub data: MarketSnapshot,
6536    pub meta: ResponseMeta,
6537}
6538
6539#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6540#[non_exhaustive]
6541pub struct GetMarketTopHoldersResponse {
6542    pub object: String,
6543    pub data: MarketTopHolders,
6544    pub meta: ResponseMeta,
6545}
6546
6547#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6548#[non_exhaustive]
6549pub struct GetMarketWalletsInOutResponse {
6550    pub object: String,
6551    pub data: MarketWalletsInOut,
6552    pub meta: ResponseMeta,
6553}
6554
6555/// A value this release does not know is kept in `Other`, so a new value never fails a response.
6556#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
6557#[non_exhaustive]
6558pub enum GetMarketWalletsInOutWindow {
6559    /// `24h`
6560    #[serde(rename = "24h")]
6561    V24h,
6562    /// `7d`
6563    #[serde(rename = "7d")]
6564    V7d,
6565    /// A value this release does not know, kept as sent.
6566    #[serde(untagged)]
6567    Other(String),
6568}
6569
6570impl GetMarketWalletsInOutWindow {
6571    /// The value as the API spells it.
6572    pub fn as_str(&self) -> &str {
6573        match self {
6574            Self::V24h => "24h",
6575            Self::V7d => "7d",
6576            Self::Other(value) => value,
6577        }
6578    }
6579}
6580
6581impl From<&str> for GetMarketWalletsInOutWindow {
6582    fn from(value: &str) -> Self {
6583        match value {
6584            "24h" => Self::V24h,
6585            "7d" => Self::V7d,
6586            other => Self::Other(other.to_owned()),
6587        }
6588    }
6589}
6590
6591impl std::fmt::Display for GetMarketWalletsInOutWindow {
6592    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6593        f.write_str(self.as_str())
6594    }
6595}
6596
6597impl AsRef<str> for GetMarketWalletsInOutWindow {
6598    fn as_ref(&self) -> &str {
6599        self.as_str()
6600    }
6601}
6602
6603#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6604#[non_exhaustive]
6605pub struct GetMonthlyReportSnapshotResponse {
6606    pub object: String,
6607    pub data: ReportSnapshot,
6608    pub meta: ResponseMeta,
6609}
6610
6611#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6612#[non_exhaustive]
6613pub struct GetPickOfTheDayArchiveResponse {
6614    pub object: String,
6615    pub data: PickOfTheDayArchive,
6616    pub meta: ResponseMeta,
6617}
6618
6619#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6620#[non_exhaustive]
6621pub struct GetPickOfTheDayLedgerEntryResponse {
6622    pub object: String,
6623    pub data: PickOfTheDayLedgerEntry,
6624    pub meta: ResponseMeta,
6625}
6626
6627#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6628#[non_exhaustive]
6629pub struct GetPickOfTheDayLedgerResponse {
6630    pub object: String,
6631    pub data: PickOfTheDayLedger,
6632    pub meta: ResponseMeta,
6633}
6634
6635#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6636#[non_exhaustive]
6637pub struct GetPickOfTheDayResponse {
6638    pub object: String,
6639    pub data: serde_json::Value,
6640    pub meta: ResponseMeta,
6641}
6642
6643#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6644#[non_exhaustive]
6645pub struct GetPickOfTheDayStatsResponse {
6646    pub object: String,
6647    pub data: PickOfTheDayStats,
6648    pub meta: ResponseMeta,
6649}
6650
6651#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6652#[non_exhaustive]
6653pub struct GetPlatformsResponse {
6654    pub object: String,
6655    pub data: Platforms,
6656    pub meta: ResponseMeta,
6657}
6658
6659#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6660#[non_exhaustive]
6661pub struct GetPositionTimelineByIdResponse {
6662    pub object: String,
6663    pub data: Vec<PositionTimelineEvent>,
6664    pub has_more: bool,
6665    #[serde(default, skip_serializing_if = "Option::is_none")]
6666    pub next_cursor: Option<String>,
6667    /// Total matching rows when the read model exposes a count; the key is absent when it does not.
6668    #[serde(default, skip_serializing_if = "Option::is_none")]
6669    pub total: Option<i64>,
6670    pub meta: ResponseMeta,
6671}
6672
6673#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6674#[non_exhaustive]
6675pub struct GetPositionTimelineResponse {
6676    pub object: String,
6677    pub data: Vec<PositionTimelineEvent>,
6678    pub has_more: bool,
6679    #[serde(default, skip_serializing_if = "Option::is_none")]
6680    pub next_cursor: Option<String>,
6681    /// Total matching rows when the read model exposes a count; the key is absent when it does not.
6682    #[serde(default, skip_serializing_if = "Option::is_none")]
6683    pub total: Option<i64>,
6684    pub meta: ResponseMeta,
6685}
6686
6687#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6688#[non_exhaustive]
6689pub struct GetReportsResponse {
6690    pub object: String,
6691    pub data: ReportSnapshot,
6692    pub meta: ResponseMeta,
6693}
6694
6695#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6696#[non_exhaustive]
6697pub struct GetResolutionReportResponse {
6698    pub object: String,
6699    pub data: ResolutionReport,
6700    pub meta: ResponseMeta,
6701}
6702
6703#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6704#[non_exhaustive]
6705pub struct GetSportLeaderboardResponse {
6706    pub object: String,
6707    pub data: SportLeaderboard,
6708    pub meta: ResponseMeta,
6709}
6710
6711#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6712#[non_exhaustive]
6713pub struct GetSuspiciousTradeResponse {
6714    pub object: String,
6715    pub data: SuspiciousTrade,
6716    pub meta: ResponseMeta,
6717}
6718
6719#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6720#[non_exhaustive]
6721pub struct GetTraderCategoryRecordsResponse {
6722    pub object: String,
6723    pub data: TraderCategoryRecords,
6724    pub meta: ResponseMeta,
6725}
6726
6727#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6728#[non_exhaustive]
6729pub struct GetTraderContextResponse {
6730    pub object: String,
6731    pub data: TraderContext,
6732    pub meta: ResponseMeta,
6733}
6734
6735#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6736#[non_exhaustive]
6737pub struct GetTraderExportSnapshotResponse {
6738    pub object: String,
6739    pub data: TraderExportSnapshot,
6740    pub meta: ResponseMeta,
6741}
6742
6743#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6744#[non_exhaustive]
6745pub struct GetTraderGradeAtResponse {
6746    pub object: String,
6747    pub data: TraderGradeAt,
6748    pub meta: ResponseMeta,
6749}
6750
6751#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6752#[non_exhaustive]
6753pub struct GetTraderPnlResponse {
6754    pub object: String,
6755    pub data: TraderPnl,
6756    pub meta: ResponseMeta,
6757}
6758
6759#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6760#[non_exhaustive]
6761pub struct GetTraderResponse {
6762    pub object: String,
6763    pub data: Trader,
6764    pub meta: ResponseMeta,
6765}
6766
6767#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6768#[non_exhaustive]
6769pub struct GetWebhookResponse {
6770    pub object: String,
6771    pub data: WebhookEndpoint,
6772    pub meta: ResponseMeta,
6773}
6774
6775#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6776#[non_exhaustive]
6777pub struct GetWebhookVerificationAttemptResponse {
6778    pub object: String,
6779    pub data: WebhookVerificationAttempt,
6780    pub meta: ResponseMeta,
6781}
6782
6783#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6784#[non_exhaustive]
6785pub struct GetWeeklyReportSnapshotResponse {
6786    pub object: String,
6787    pub data: ReportSnapshot,
6788    pub meta: ResponseMeta,
6789}
6790
6791#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6792#[non_exhaustive]
6793pub struct GetWhaleTradeResponse {
6794    pub object: String,
6795    pub data: LargeTradeDetail,
6796    pub meta: ResponseMeta,
6797}
6798
6799/// A value this release does not know is kept in `Other`, so a new value never fails a response.
6800#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
6801#[non_exhaustive]
6802pub enum Grade {
6803    /// `S`
6804    #[serde(rename = "S")]
6805    S,
6806    /// `A`
6807    #[serde(rename = "A")]
6808    A,
6809    /// `B`
6810    #[serde(rename = "B")]
6811    B,
6812    /// `C`
6813    #[serde(rename = "C")]
6814    C,
6815    /// `D`
6816    #[serde(rename = "D")]
6817    D,
6818    /// `F`
6819    #[serde(rename = "F")]
6820    F,
6821    /// A value this release does not know, kept as sent.
6822    #[serde(untagged)]
6823    Other(String),
6824}
6825
6826impl Grade {
6827    /// The value as the API spells it.
6828    pub fn as_str(&self) -> &str {
6829        match self {
6830            Self::S => "S",
6831            Self::A => "A",
6832            Self::B => "B",
6833            Self::C => "C",
6834            Self::D => "D",
6835            Self::F => "F",
6836            Self::Other(value) => value,
6837        }
6838    }
6839}
6840
6841impl From<&str> for Grade {
6842    fn from(value: &str) -> Self {
6843        match value {
6844            "S" => Self::S,
6845            "A" => Self::A,
6846            "B" => Self::B,
6847            "C" => Self::C,
6848            "D" => Self::D,
6849            "F" => Self::F,
6850            other => Self::Other(other.to_owned()),
6851        }
6852    }
6853}
6854
6855impl std::fmt::Display for Grade {
6856    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6857        f.write_str(self.as_str())
6858    }
6859}
6860
6861impl AsRef<str> for Grade {
6862    fn as_ref(&self) -> &str {
6863        self.as_str()
6864    }
6865}
6866
6867/// A value this release does not know is kept in `Other`, so a new value never fails a response.
6868#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
6869#[non_exhaustive]
6870pub enum GradeAtTradeStatus {
6871    /// `graded`
6872    #[serde(rename = "graded")]
6873    Graded,
6874    /// `ungraded`
6875    #[serde(rename = "ungraded")]
6876    Ungraded,
6877    /// `unknown`
6878    #[serde(rename = "unknown")]
6879    Unknown,
6880    /// A value this release does not know, kept as sent.
6881    #[serde(untagged)]
6882    Other(String),
6883}
6884
6885impl GradeAtTradeStatus {
6886    /// The value as the API spells it.
6887    pub fn as_str(&self) -> &str {
6888        match self {
6889            Self::Graded => "graded",
6890            Self::Ungraded => "ungraded",
6891            Self::Unknown => "unknown",
6892            Self::Other(value) => value,
6893        }
6894    }
6895}
6896
6897impl From<&str> for GradeAtTradeStatus {
6898    fn from(value: &str) -> Self {
6899        match value {
6900            "graded" => Self::Graded,
6901            "ungraded" => Self::Ungraded,
6902            "unknown" => Self::Unknown,
6903            other => Self::Other(other.to_owned()),
6904        }
6905    }
6906}
6907
6908impl std::fmt::Display for GradeAtTradeStatus {
6909    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6910        f.write_str(self.as_str())
6911    }
6912}
6913
6914impl AsRef<str> for GradeAtTradeStatus {
6915    fn as_ref(&self) -> &str {
6916        self.as_str()
6917    }
6918}
6919
6920/// A value this release does not know is kept in `Other`, so a new value never fails a response.
6921#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
6922#[non_exhaustive]
6923pub enum GradeBasis {
6924    /// `at_resolution`
6925    #[serde(rename = "at_resolution")]
6926    AtResolution,
6927    /// `current`
6928    #[serde(rename = "current")]
6929    Current,
6930    /// A value this release does not know, kept as sent.
6931    #[serde(untagged)]
6932    Other(String),
6933}
6934
6935impl GradeBasis {
6936    /// The value as the API spells it.
6937    pub fn as_str(&self) -> &str {
6938        match self {
6939            Self::AtResolution => "at_resolution",
6940            Self::Current => "current",
6941            Self::Other(value) => value,
6942        }
6943    }
6944}
6945
6946impl From<&str> for GradeBasis {
6947    fn from(value: &str) -> Self {
6948        match value {
6949            "at_resolution" => Self::AtResolution,
6950            "current" => Self::Current,
6951            other => Self::Other(other.to_owned()),
6952        }
6953    }
6954}
6955
6956impl std::fmt::Display for GradeBasis {
6957    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6958        f.write_str(self.as_str())
6959    }
6960}
6961
6962impl AsRef<str> for GradeBasis {
6963    fn as_ref(&self) -> &str {
6964        self.as_str()
6965    }
6966}
6967
6968/// A value this release does not know is kept in `Other`, so a new value never fails a response.
6969#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
6970#[non_exhaustive]
6971pub enum Granularity {
6972    /// `daily`
6973    #[serde(rename = "daily")]
6974    Daily,
6975    /// `weekly`
6976    #[serde(rename = "weekly")]
6977    Weekly,
6978    /// `monthly`
6979    #[serde(rename = "monthly")]
6980    Monthly,
6981    /// A value this release does not know, kept as sent.
6982    #[serde(untagged)]
6983    Other(String),
6984}
6985
6986impl Granularity {
6987    /// The value as the API spells it.
6988    pub fn as_str(&self) -> &str {
6989        match self {
6990            Self::Daily => "daily",
6991            Self::Weekly => "weekly",
6992            Self::Monthly => "monthly",
6993            Self::Other(value) => value,
6994        }
6995    }
6996}
6997
6998impl From<&str> for Granularity {
6999    fn from(value: &str) -> Self {
7000        match value {
7001            "daily" => Self::Daily,
7002            "weekly" => Self::Weekly,
7003            "monthly" => Self::Monthly,
7004            other => Self::Other(other.to_owned()),
7005        }
7006    }
7007}
7008
7009impl std::fmt::Display for Granularity {
7010    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7011        f.write_str(self.as_str())
7012    }
7013}
7014
7015impl AsRef<str> for Granularity {
7016    fn as_ref(&self) -> &str {
7017        self.as_str()
7018    }
7019}
7020
7021/// Current category evidence, independent of the global grade. Pick of the Day stamps only the served display roster; frozen entry snapshots remain unchanged.
7022#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7023#[non_exhaustive]
7024pub struct HolderCategoryEvidence {
7025    pub status: Status,
7026    #[serde(default, skip_serializing_if = "Option::is_none")]
7027    pub canonical_category: Option<String>,
7028    #[serde(default, skip_serializing_if = "Option::is_none")]
7029    pub skill: Option<CategorySkillV2>,
7030}
7031
7032/// A value this release does not know is kept in `Other`, so a new value never fails a response.
7033#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
7034#[non_exhaustive]
7035pub enum IdentityStatus {
7036    /// `resolved`
7037    #[serde(rename = "resolved")]
7038    Resolved,
7039    /// `infrastructure`
7040    #[serde(rename = "infrastructure")]
7041    Infrastructure,
7042    /// `unavailable`
7043    #[serde(rename = "unavailable")]
7044    Unavailable,
7045    /// A value this release does not know, kept as sent.
7046    #[serde(untagged)]
7047    Other(String),
7048}
7049
7050impl IdentityStatus {
7051    /// The value as the API spells it.
7052    pub fn as_str(&self) -> &str {
7053        match self {
7054            Self::Resolved => "resolved",
7055            Self::Infrastructure => "infrastructure",
7056            Self::Unavailable => "unavailable",
7057            Self::Other(value) => value,
7058        }
7059    }
7060}
7061
7062impl From<&str> for IdentityStatus {
7063    fn from(value: &str) -> Self {
7064        match value {
7065            "resolved" => Self::Resolved,
7066            "infrastructure" => Self::Infrastructure,
7067            "unavailable" => Self::Unavailable,
7068            other => Self::Other(other.to_owned()),
7069        }
7070    }
7071}
7072
7073impl std::fmt::Display for IdentityStatus {
7074    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7075        f.write_str(self.as_str())
7076    }
7077}
7078
7079impl AsRef<str> for IdentityStatus {
7080    fn as_ref(&self) -> &str {
7081        self.as_str()
7082    }
7083}
7084
7085/// A value this release does not know is kept in `Other`, so a new value never fails a response.
7086#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
7087#[non_exhaustive]
7088pub enum Kind {
7089    /// `sports`
7090    #[serde(rename = "sports")]
7091    Sports,
7092    /// `esports`
7093    #[serde(rename = "esports")]
7094    Esports,
7095    /// A value this release does not know, kept as sent.
7096    #[serde(untagged)]
7097    Other(String),
7098}
7099
7100impl Kind {
7101    /// The value as the API spells it.
7102    pub fn as_str(&self) -> &str {
7103        match self {
7104            Self::Sports => "sports",
7105            Self::Esports => "esports",
7106            Self::Other(value) => value,
7107        }
7108    }
7109}
7110
7111impl From<&str> for Kind {
7112    fn from(value: &str) -> Self {
7113        match value {
7114            "sports" => Self::Sports,
7115            "esports" => Self::Esports,
7116            other => Self::Other(other.to_owned()),
7117        }
7118    }
7119}
7120
7121impl std::fmt::Display for Kind {
7122    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7123        f.write_str(self.as_str())
7124    }
7125}
7126
7127impl AsRef<str> for Kind {
7128    fn as_ref(&self) -> &str {
7129        self.as_str()
7130    }
7131}
7132
7133#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7134#[non_exhaustive]
7135pub struct LargeExportPolicy {
7136    pub mode: String,
7137    pub current_internal_route: String,
7138    /// Programmatic API-key-gated export routes (submit/status/download/cancel) and supported formats (json, ndjson, csv).
7139    pub v1_async: LargeExportPolicyV1Async,
7140    pub direct_streaming: LargeExportPolicyDirectStreaming,
7141    pub async_job: LargeExportPolicyAsyncJob,
7142    pub rate_limit: LargeExportPolicyRateLimit,
7143}
7144
7145#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7146#[non_exhaustive]
7147pub struct LargeExportPolicyAsyncJob {
7148    pub available_when: String,
7149    pub status_values: Vec<String>,
7150    pub retention: String,
7151}
7152
7153#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7154#[non_exhaustive]
7155pub struct LargeExportPolicyDirectStreaming {
7156    pub available_when: String,
7157    pub backpressure: String,
7158    pub chunk_size_rows: i64,
7159}
7160
7161#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7162#[non_exhaustive]
7163pub struct LargeExportPolicyRateLimit {
7164    pub daily_cap_per_user: i64,
7165    pub per_address_hourly_cap: i64,
7166}
7167
7168/// Programmatic API-key-gated export routes (submit/status/download/cancel) and supported formats (json, ndjson, csv).
7169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7170#[non_exhaustive]
7171pub struct LargeExportPolicyV1Async {
7172    /// POST route template to submit an export job. fresh=true asks for a snapshot read after the submit instead of reusing a finished one.
7173    pub submit_route: String,
7174    /// GET route template to poll job status.
7175    pub status_route: String,
7176    /// GET route template that 302-redirects to the file.
7177    pub download_route: String,
7178    /// POST route template to cancel a queued or running job.
7179    pub cancel_route: String,
7180    /// Supported ?format= values.
7181    pub formats: Vec<Format>,
7182    /// Possible job status values.
7183    pub status_values: Vec<TraderExportJobDataStatus>,
7184    /// How long a finished export is retained before expiry.
7185    pub retention: String,
7186}
7187
7188#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7189#[non_exhaustive]
7190pub struct LargePosition {
7191    /// Composite prefixed ID `pos_<wallet>:<condition_id>:<outcome_index>`.
7192    pub id: String,
7193    /// Provider discriminator. Always polymarket.
7194    pub platform: String,
7195    /// 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.
7196    #[serde(default, skip_serializing_if = "Option::is_none")]
7197    pub total_size_usd: Option<f64>,
7198    /// Provider unrealized mark-to-market P&L (Polymarket cashPnl) for that same one outcome. An absent key means unavailable, not break-even.
7199    #[serde(default, skip_serializing_if = "Option::is_none")]
7200    pub position_unrealized_pnl: Option<f64>,
7201    /// 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.
7202    #[serde(default, skip_serializing_if = "Option::is_none")]
7203    pub combined_value_usd: Option<f64>,
7204    /// The wallet's unrealized P&L across every outcome it holds in this market. Equals position_unrealized_pnl unless is_two_sided is true.
7205    #[serde(default, skip_serializing_if = "Option::is_none")]
7206    pub combined_unrealized_pnl: Option<f64>,
7207    /// Whether the wallet holds shares on both outcomes of this market.
7208    pub is_two_sided: bool,
7209    /// 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.
7210    pub holdings: Vec<LargePositionHoldingsItem>,
7211    /// Live share count for this position.
7212    pub share_count: f64,
7213    /// Volume-weighted entry price.
7214    #[serde(default, skip_serializing_if = "Option::is_none")]
7215    pub avg_entry_price: Option<f64>,
7216    /// Latest provider mark price for the position's token.
7217    #[serde(default, skip_serializing_if = "Option::is_none")]
7218    pub current_price: Option<f64>,
7219    /// Backend-resolved outcome label (provider outcome, else Yes/No from the binary index).
7220    #[serde(default, skip_serializing_if = "Option::is_none")]
7221    pub outcome_label: Option<String>,
7222    /// The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets).
7223    #[serde(default)]
7224    pub token_id: Option<String>,
7225    /// Legs collapsed into this representative row for one (wallet, event, outcome side) group. 1 means standalone.
7226    pub event_leg_count: i64,
7227    /// 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.
7228    #[serde(default, skip_serializing_if = "Option::is_none")]
7229    pub event_total_value_usd: Option<f64>,
7230    pub first_seen_at: String,
7231    pub last_updated_at: String,
7232    pub trader: LargePositionTrader,
7233    pub market: LargePositionMarket,
7234}
7235
7236#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7237#[non_exhaustive]
7238pub struct LargePositionHoldingsItem {
7239    /// 0 = Yes, 1 = No.
7240    pub outcome_index: i64,
7241    /// The market's label for this outcome.
7242    #[serde(default, skip_serializing_if = "Option::is_none")]
7243    pub outcome_label: Option<String>,
7244    /// Polymarket CLOB token id for this outcome; null for an unsynced market.
7245    #[serde(default)]
7246    pub token_id: Option<String>,
7247    /// Shares held on this outcome.
7248    pub share_count: f64,
7249    /// Provider average entry price for this outcome.
7250    #[serde(default, skip_serializing_if = "Option::is_none")]
7251    pub avg_entry_price: Option<f64>,
7252    /// Provider mark price for this outcome.
7253    #[serde(default, skip_serializing_if = "Option::is_none")]
7254    pub current_price: Option<f64>,
7255    /// Provider currentValue for this outcome. An absent key means unavailable, not zero.
7256    #[serde(default, skip_serializing_if = "Option::is_none")]
7257    pub value_usd: Option<f64>,
7258    /// Provider unrealized P&L for this outcome. An absent key means unavailable, not break-even.
7259    #[serde(default, skip_serializing_if = "Option::is_none")]
7260    pub unrealized_pnl: Option<f64>,
7261}
7262
7263#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7264#[non_exhaustive]
7265pub struct LargePositionMarket {
7266    /// Prefixed ID (`mkt_...`).
7267    pub id: String,
7268    pub condition_id: String,
7269    #[serde(default, skip_serializing_if = "Option::is_none")]
7270    pub title: Option<String>,
7271    #[serde(default, skip_serializing_if = "Option::is_none")]
7272    pub slug: Option<String>,
7273    #[serde(default, skip_serializing_if = "Option::is_none")]
7274    pub event_slug: Option<String>,
7275    #[serde(default, skip_serializing_if = "Option::is_none")]
7276    pub category: Option<String>,
7277}
7278
7279#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7280#[non_exhaustive]
7281pub struct LargePositionTrader {
7282    /// Prefixed ID (`trd_...`).
7283    pub id: String,
7284    pub address: String,
7285    #[serde(default, skip_serializing_if = "Option::is_none")]
7286    pub username: Option<String>,
7287    #[serde(default, skip_serializing_if = "Option::is_none")]
7288    pub grade: Option<Grade>,
7289    /// 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.
7290    #[serde(default, skip_serializing_if = "Option::is_none")]
7291    pub win_rate: Option<f64>,
7292    /// 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.
7293    #[serde(default, skip_serializing_if = "Option::is_none")]
7294    pub pnl: Option<f64>,
7295    /// 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).
7296    #[serde(default, skip_serializing_if = "Option::is_none")]
7297    pub in_scope_realized_pnl: Option<f64>,
7298    /// 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.
7299    #[serde(default, skip_serializing_if = "Option::is_none")]
7300    pub markets_traded: Option<i64>,
7301}
7302
7303/// `large_positions_updated` data: one large-positions refresh finished.
7304#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7305#[non_exhaustive]
7306pub struct LargePositionsUpdatedData {
7307    /// Positions the refresh published.
7308    pub count: i64,
7309}
7310
7311#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7312#[non_exhaustive]
7313pub struct LargeTrade {
7314    /// Prefixed ID (wt_...).
7315    pub id: String,
7316    pub traded_at: String,
7317    pub size_usd: f64,
7318    pub side: Side,
7319    /// 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).
7320    #[serde(default)]
7321    pub outcome: Option<String>,
7322    /// 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).
7323    #[serde(default)]
7324    pub token_id: Option<String>,
7325    pub price: f64,
7326    /// 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.
7327    pub review_score: f64,
7328    /// 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.
7329    pub signal_score: f64,
7330    /// 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.
7331    #[serde(default)]
7332    pub recorded_review_score: Option<f64>,
7333    /// 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.
7334    #[serde(default)]
7335    pub recorded_signal_score: Option<f64>,
7336    /// Persisted live suspicion score from the scorer. Null when the row has no persisted score.
7337    #[serde(default)]
7338    pub suspicion_score: Option<i64>,
7339    /// Persisted scorer track. Null when a legacy row has no stored track label.
7340    #[serde(default)]
7341    pub suspicion_track: Option<SuspicionTrack>,
7342    /// 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.
7343    #[serde(default, skip_serializing_if = "Option::is_none")]
7344    pub market_volume_share: Option<f64>,
7345    pub trader: LargeTradeTrader,
7346    pub market: LargeTradeMarket,
7347}
7348
7349#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7350#[non_exhaustive]
7351pub struct LargeTradeDetail {
7352    #[serde(flatten)]
7353    pub large_trade: LargeTrade,
7354    pub counterparty_analysis: CounterpartyAnalysis,
7355}
7356
7357#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7358#[non_exhaustive]
7359pub struct LargeTradeHistoryMeta {
7360    /// 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.
7361    pub request_id: String,
7362    pub cached: bool,
7363    /// Cache age in seconds; the key is absent when the response was not cached.
7364    #[serde(default, skip_serializing_if = "Option::is_none")]
7365    pub cache_age_s: Option<i64>,
7366    pub source: LargeTradeHistoryMetaSource,
7367    pub completeness: LargeTradeHistoryMetaCompleteness,
7368}
7369
7370#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7371#[non_exhaustive]
7372pub struct LargeTradeHistoryMetaCompleteness {
7373    pub status: String,
7374    /// Explains that local replay completeness can vary by market and time window.
7375    pub reason: String,
7376}
7377
7378#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7379#[non_exhaustive]
7380pub struct LargeTradeHistoryMetaSource {
7381    pub kind: String,
7382    pub table: String,
7383    pub provider_fetch_at_request_time: bool,
7384}
7385
7386/// `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.
7387#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7388#[non_exhaustive]
7389pub struct LargeTradeInsertedV2Data {
7390    /// 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`.
7391    pub event_id: String,
7392    /// Numeric id of the trade. `GET /api/v1/large-trades/{id}` accepts it.
7393    pub whale_alert_id: i64,
7394    /// Polymarket condition id of the market.
7395    pub condition_id: String,
7396    /// 0xinsider's numeric id for the wallet.
7397    pub trader_id: i64,
7398    /// Address of the wallet that made the trade.
7399    pub wallet: String,
7400    /// The wallet's grade when the event was published; `null` when it has none.
7401    #[serde(default)]
7402    pub grade: Option<Grade>,
7403    /// USD notional of the trade; decimal string.
7404    pub size_usd: String,
7405    /// Shares traded; decimal string.
7406    pub shares: String,
7407    /// Price paid per share; decimal string.
7408    pub price: String,
7409    pub side: Side,
7410    /// Polymarket's index of the outcome traded.
7411    pub outcome_index: i64,
7412    /// When the trade filled on Polymarket. The envelope's `created_at` is this instant.
7413    pub traded_at: String,
7414    pub platform: String,
7415}
7416
7417#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7418#[non_exhaustive]
7419pub struct LargeTradeMarket {
7420    pub id: String,
7421    pub condition_id: String,
7422    pub title: String,
7423    #[serde(default, skip_serializing_if = "Option::is_none")]
7424    pub slug: Option<String>,
7425    /// Provider-backed market_canonical category.
7426    #[serde(default, skip_serializing_if = "Option::is_none")]
7427    pub category: Option<String>,
7428}
7429
7430/// All present fields narrow large_trade_inserted_v2 delivery. Grade is observed at publication; ungraded trades do not match min_grade. An empty object matches every large trade.
7431#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
7432pub struct LargeTradeSubscriptionFilters {
7433    /// Raw provider condition ID or mkt_-prefixed market ID.
7434    #[serde(default, skip_serializing_if = "Option::is_none")]
7435    pub condition_id: Option<String>,
7436    /// Polymarket wallet address; matching is case-insensitive.
7437    #[serde(default, skip_serializing_if = "Option::is_none")]
7438    pub wallet: Option<String>,
7439    /// S is best; ungraded trades do not match.
7440    #[serde(default, skip_serializing_if = "Option::is_none")]
7441    pub min_grade: Option<Grade>,
7442    /// Positive USD notional as an exact decimal string.
7443    #[serde(default, skip_serializing_if = "Option::is_none")]
7444    pub min_size_usd: Option<String>,
7445}
7446
7447#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7448#[non_exhaustive]
7449pub struct LargeTradeTrader {
7450    pub id: String,
7451    pub address: String,
7452    #[serde(default, skip_serializing_if = "Option::is_none")]
7453    pub username: Option<String>,
7454    /// The trader's grade today, on every row however old. For what the grade was when the trade happened, read grade_at_trade.
7455    #[serde(default, skip_serializing_if = "Option::is_none")]
7456    pub grade: Option<Grade>,
7457    /// 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.
7458    #[serde(default)]
7459    pub grade_at_trade: Option<Grade>,
7460    /// 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.
7461    pub grade_at_trade_status: GradeAtTradeStatus,
7462}
7463
7464/// `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).
7465#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7466#[non_exhaustive]
7467pub struct LargeTradesInsertedData {
7468    /// Large trades the producing batch admitted.
7469    pub count: i64,
7470}
7471
7472#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7473#[non_exhaustive]
7474pub struct LeaderboardEntry {
7475    pub id: String,
7476    pub address: String,
7477    #[serde(default, skip_serializing_if = "Option::is_none")]
7478    pub username: Option<String>,
7479    #[serde(default, skip_serializing_if = "Option::is_none")]
7480    pub grade: Option<Grade>,
7481    /// Hot-streak tier (trailing-7d cross-sectional percentile); a separate axis from the all-time grade. Omitted when there is no recent activity.
7482    #[serde(default, skip_serializing_if = "Option::is_none")]
7483    pub streak_tier: Option<StreakTier>,
7484    #[serde(default, skip_serializing_if = "Option::is_none")]
7485    pub score: Option<f64>,
7486    /// 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.
7487    #[serde(default, skip_serializing_if = "Option::is_none")]
7488    pub pnl: Option<f64>,
7489    /// 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.
7490    #[serde(default, skip_serializing_if = "Option::is_none")]
7491    pub realized_pnl: Option<f64>,
7492    /// 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.
7493    #[serde(default, skip_serializing_if = "Option::is_none")]
7494    pub pnl_correction: Option<PnlCorrection>,
7495    /// 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).
7496    #[serde(default, skip_serializing_if = "Option::is_none")]
7497    pub volume: Option<f64>,
7498    /// 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.
7499    #[serde(default, skip_serializing_if = "Option::is_none")]
7500    pub markets_traded: Option<i64>,
7501    /// 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.
7502    #[serde(default, skip_serializing_if = "Option::is_none")]
7503    pub win_rate: Option<f64>,
7504    /// 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.
7505    #[serde(default, skip_serializing_if = "Option::is_none")]
7506    pub in_scope: Option<TraderPnlInScope>,
7507    /// 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.
7508    #[serde(default, skip_serializing_if = "Option::is_none")]
7509    pub price_edge: Option<LeaderboardPriceEdge>,
7510    /// 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.
7511    #[serde(default, skip_serializing_if = "Option::is_none")]
7512    pub strategy_type: Option<String>,
7513    /// Provider platform. Always polymarket.
7514    pub platform: String,
7515    /// 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.
7516    #[serde(default, skip_serializing_if = "Option::is_none")]
7517    pub last_active: Option<String>,
7518}
7519
7520#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7521#[non_exhaustive]
7522pub struct LeaderboardLeagues {
7523    pub leagues: Vec<LeaderboardLeaguesLeaguesItem>,
7524    pub min_ranked: i64,
7525    pub min_resolved: i64,
7526    pub refreshed_at: String,
7527}
7528
7529#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7530#[non_exhaustive]
7531pub struct LeaderboardLeaguesLeaguesItem {
7532    pub category: String,
7533    pub name: String,
7534    pub ranked_traders: i64,
7535    pub slug: String,
7536    pub sport: String,
7537    pub total_traders: i64,
7538}
7539
7540/// 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.
7541#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7542#[non_exhaustive]
7543pub struct LeaderboardPriceEdge {
7544    /// Settled sports and esports markets of $20 or more at a known entry price that the edge is measured over.
7545    pub markets: i64,
7546    /// Share of those markets whose bought side won, 0-1.
7547    pub hit_rate: f64,
7548    /// Mean entry price paid, 0-1.
7549    pub avg_price: f64,
7550    /// hit_rate minus avg_price, full precision. The value sort=edge orders by.
7551    pub edge: f64,
7552    /// 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.
7553    pub status: SportLeaderboardRowsPriceEdgeStatus,
7554    /// 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.
7555    #[serde(default, skip_serializing_if = "Option::is_none")]
7556    pub hold: Option<String>,
7557}
7558
7559/// A value this release does not know is kept in `Other`, so a new value never fails a response.
7560#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
7561#[non_exhaustive]
7562pub enum Lifecycle {
7563    /// `live`
7564    #[serde(rename = "live")]
7565    Live,
7566    /// `settled`
7567    #[serde(rename = "settled")]
7568    Settled,
7569    /// `indeterminate`
7570    #[serde(rename = "indeterminate")]
7571    Indeterminate,
7572    /// A value this release does not know, kept as sent.
7573    #[serde(untagged)]
7574    Other(String),
7575}
7576
7577impl Lifecycle {
7578    /// The value as the API spells it.
7579    pub fn as_str(&self) -> &str {
7580        match self {
7581            Self::Live => "live",
7582            Self::Settled => "settled",
7583            Self::Indeterminate => "indeterminate",
7584            Self::Other(value) => value,
7585        }
7586    }
7587}
7588
7589impl From<&str> for Lifecycle {
7590    fn from(value: &str) -> Self {
7591        match value {
7592            "live" => Self::Live,
7593            "settled" => Self::Settled,
7594            "indeterminate" => Self::Indeterminate,
7595            other => Self::Other(other.to_owned()),
7596        }
7597    }
7598}
7599
7600impl std::fmt::Display for Lifecycle {
7601    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7602        f.write_str(self.as_str())
7603    }
7604}
7605
7606impl AsRef<str> for Lifecycle {
7607    fn as_ref(&self) -> &str {
7608        self.as_str()
7609    }
7610}
7611
7612#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7613#[non_exhaustive]
7614pub struct ListCategoryLeadersResponse {
7615    pub object: String,
7616    pub data: Vec<CategoryLeader>,
7617    pub has_more: bool,
7618    #[serde(default, skip_serializing_if = "Option::is_none")]
7619    pub next_cursor: Option<String>,
7620    /// Number of rows returned: up to three per category.
7621    #[serde(default, skip_serializing_if = "Option::is_none")]
7622    pub total: Option<i64>,
7623    pub meta: ResponseMeta,
7624}
7625
7626#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7627#[non_exhaustive]
7628pub struct ListGameMarketsResponse {
7629    pub data: Vec<ListGameMarketsResponseDataItem>,
7630    pub event_slug: String,
7631    pub families: Vec<ListGameMarketsResponseFamiliesItem>,
7632    pub has_more: bool,
7633    pub meta: ResponseMeta,
7634    #[serde(default, skip_serializing_if = "Option::is_none")]
7635    pub next_cursor: Option<String>,
7636    pub object: String,
7637}
7638
7639#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7640#[non_exhaustive]
7641pub struct ListGameMarketsResponseDataItem {
7642    pub condition_id: String,
7643    pub event_slug: String,
7644    #[serde(default, skip_serializing_if = "Option::is_none")]
7645    pub group_item_title: Option<String>,
7646    pub id: String,
7647    #[serde(default, skip_serializing_if = "Option::is_none")]
7648    pub line: Option<f64>,
7649    #[serde(default, skip_serializing_if = "Option::is_none")]
7650    pub line_outcome_index: Option<i64>,
7651    #[serde(default, skip_serializing_if = "Option::is_none")]
7652    pub negative_risk: Option<bool>,
7653    pub outcomes: Vec<ListGameMarketsResponseDataItemOutcomesItem>,
7654    #[serde(default, skip_serializing_if = "Option::is_none")]
7655    pub platform: Option<String>,
7656    #[serde(default, skip_serializing_if = "Option::is_none")]
7657    pub slug: Option<String>,
7658    #[serde(default, skip_serializing_if = "Option::is_none")]
7659    pub sports_market_type: Option<String>,
7660    pub status: String,
7661    #[serde(default, skip_serializing_if = "Option::is_none")]
7662    pub title: Option<String>,
7663    #[serde(default, skip_serializing_if = "Option::is_none")]
7664    pub sharp_money: Option<ListGameMarketsResponseDataItemSharpMoney>,
7665}
7666
7667#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7668#[non_exhaustive]
7669pub struct ListGameMarketsResponseDataItemOutcomesItem {
7670    pub index: i64,
7671    #[serde(default, skip_serializing_if = "Option::is_none")]
7672    pub label: Option<String>,
7673    #[serde(default, skip_serializing_if = "Option::is_none")]
7674    pub token_id: Option<String>,
7675}
7676
7677#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7678#[non_exhaustive]
7679pub struct ListGameMarketsResponseDataItemSharpMoney {
7680    #[serde(default)]
7681    pub money_as_of: Option<String>,
7682    pub outcomes: Vec<ListGameMarketsResponseDataItemSharpMoneyOutcomesItem>,
7683    pub status: GameSharpMoneyStatus,
7684    #[serde(default)]
7685    pub trader_count: Option<i64>,
7686}
7687
7688#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7689#[non_exhaustive]
7690pub struct ListGameMarketsResponseDataItemSharpMoneyOutcomesItem {
7691    pub index: i64,
7692    pub usd: f64,
7693    pub wallets: ListGameMarketsResponseDataItemSharpMoneyOutcomesItemWallets,
7694}
7695
7696#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7697#[non_exhaustive]
7698pub struct ListGameMarketsResponseDataItemSharpMoneyOutcomesItemWallets {
7699    pub a: i64,
7700    pub b: i64,
7701    pub s: i64,
7702}
7703
7704#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7705#[non_exhaustive]
7706pub struct ListGameMarketsResponseFamiliesItem {
7707    pub active: i64,
7708    pub markets: i64,
7709    #[serde(default, skip_serializing_if = "Option::is_none")]
7710    pub sports_market_type: Option<String>,
7711}
7712
7713#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7714#[non_exhaustive]
7715pub struct ListGameTradesResponse {
7716    pub object: String,
7717    /// Newest first.
7718    pub data: Vec<GameTrade>,
7719    /// Always false: the list is the game's newest limit fills, not a walk. Poll again for newer fills.
7720    pub has_more: bool,
7721    /// The game the rows were read for, lowercased.
7722    pub event_slug: String,
7723    /// 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.
7724    pub source_stale: bool,
7725    pub meta: ResponseMeta,
7726}
7727
7728#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7729#[non_exhaustive]
7730pub struct ListGamesResponse {
7731    pub object: String,
7732    pub data: Vec<Game>,
7733    pub has_more: bool,
7734    /// Pass as cursor for the next page. Present only when has_more is true.
7735    #[serde(default, skip_serializing_if = "Option::is_none")]
7736    pub next_cursor: Option<String>,
7737    /// 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.
7738    pub as_of: String,
7739    pub coverage: GamesCoverage,
7740    pub meta: ResponseMeta,
7741}
7742
7743/// A value this release does not know is kept in `Other`, so a new value never fails a response.
7744#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
7745#[non_exhaustive]
7746pub enum ListGamesWindow {
7747    /// `all`
7748    #[serde(rename = "all")]
7749    All,
7750    /// `now`
7751    #[serde(rename = "now")]
7752    Now,
7753    /// A value this release does not know, kept as sent.
7754    #[serde(untagged)]
7755    Other(String),
7756}
7757
7758impl ListGamesWindow {
7759    /// The value as the API spells it.
7760    pub fn as_str(&self) -> &str {
7761        match self {
7762            Self::All => "all",
7763            Self::Now => "now",
7764            Self::Other(value) => value,
7765        }
7766    }
7767}
7768
7769impl From<&str> for ListGamesWindow {
7770    fn from(value: &str) -> Self {
7771        match value {
7772            "all" => Self::All,
7773            "now" => Self::Now,
7774            other => Self::Other(other.to_owned()),
7775        }
7776    }
7777}
7778
7779impl std::fmt::Display for ListGamesWindow {
7780    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7781        f.write_str(self.as_str())
7782    }
7783}
7784
7785impl AsRef<str> for ListGamesWindow {
7786    fn as_ref(&self) -> &str {
7787        self.as_str()
7788    }
7789}
7790
7791#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7792#[non_exhaustive]
7793pub struct ListInsiderRadarResponse {
7794    pub object: String,
7795    pub data: Vec<SuspiciousTrade>,
7796    pub has_more: bool,
7797    #[serde(default, skip_serializing_if = "Option::is_none")]
7798    pub next_cursor: Option<String>,
7799    /// Total matching rows when the read model exposes a count; the key is absent when it does not.
7800    #[serde(default, skip_serializing_if = "Option::is_none")]
7801    pub total: Option<i64>,
7802    pub meta: ResponseMeta,
7803}
7804
7805#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7806#[non_exhaustive]
7807pub struct ListLargePositionsResponse {
7808    pub object: String,
7809    pub data: Vec<LargePosition>,
7810    pub has_more: bool,
7811    /// Opaque cursor for the next page; absent on the last page.
7812    #[serde(default, skip_serializing_if = "Option::is_none")]
7813    pub next_cursor: Option<String>,
7814    /// Total ranked rows when the read model exposes a count; may be absent.
7815    #[serde(default, skip_serializing_if = "Option::is_none")]
7816    pub total: Option<i64>,
7817    pub meta: ResponseMeta,
7818}
7819
7820#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7821#[non_exhaustive]
7822pub struct ListLargeTradeCounterpartyExecutionsResponse {
7823    pub object: String,
7824    pub data: CounterpartyAnalysis,
7825    pub meta: ResponseMeta,
7826}
7827
7828#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7829#[non_exhaustive]
7830pub struct ListLargeTradeCounterpartyMakersResponse {
7831    pub object: String,
7832    pub data: CounterpartyMakerPage,
7833    pub meta: ResponseMeta,
7834}
7835
7836#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7837#[non_exhaustive]
7838pub struct ListLargeTradeHistoryResponse {
7839    pub object: String,
7840    pub data: Vec<LargeTrade>,
7841    /// Writer-backed age and coverage for this page; it is part of the representation and the ETag, while transport cache facts remain in meta.
7842    pub data_quality: DataQuality,
7843    pub has_more: bool,
7844    #[serde(default, skip_serializing_if = "Option::is_none")]
7845    pub next_cursor: Option<String>,
7846    /// Total matching rows when the read model exposes a count; the key is absent when it does not.
7847    #[serde(default, skip_serializing_if = "Option::is_none")]
7848    pub total: Option<i64>,
7849    pub meta: LargeTradeHistoryMeta,
7850}
7851
7852#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7853#[non_exhaustive]
7854pub struct ListLargeTradesResponse {
7855    pub object: String,
7856    pub data: Vec<LargeTrade>,
7857    /// Writer-backed age and coverage for this page; it is part of the representation and the ETag, while transport cache facts remain in meta.
7858    pub data_quality: DataQuality,
7859    pub has_more: bool,
7860    #[serde(default, skip_serializing_if = "Option::is_none")]
7861    pub next_cursor: Option<String>,
7862    /// Total matching rows when the read model exposes a count; absent (or null) when it does not.
7863    #[serde(default, skip_serializing_if = "Option::is_none")]
7864    pub total: Option<i64>,
7865    pub meta: ResponseMeta,
7866}
7867
7868#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7869#[non_exhaustive]
7870pub struct ListLeaderboardLeaguesResponse {
7871    pub object: String,
7872    pub data: LeaderboardLeagues,
7873    pub meta: ResponseMeta,
7874}
7875
7876#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7877#[non_exhaustive]
7878pub struct ListLeaderboardResponse {
7879    pub object: String,
7880    pub data: Vec<LeaderboardEntry>,
7881    pub has_more: bool,
7882    #[serde(default, skip_serializing_if = "Option::is_none")]
7883    pub next_cursor: Option<String>,
7884    /// Total matching rows when the read model exposes a count; the key is absent when it does not.
7885    #[serde(default, skip_serializing_if = "Option::is_none")]
7886    pub total: Option<i64>,
7887    pub meta: ResponseMeta,
7888}
7889
7890/// A value this release does not know is kept in `Other`, so a new value never fails a response.
7891#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
7892#[non_exhaustive]
7893pub enum ListLeaderboardSort {
7894    /// `rank`
7895    #[serde(rename = "rank")]
7896    Rank,
7897    /// `grade`
7898    #[serde(rename = "grade")]
7899    Grade,
7900    /// `volume`
7901    #[serde(rename = "volume")]
7902    Volume,
7903    /// `predictions`
7904    #[serde(rename = "predictions")]
7905    Predictions,
7906    /// `pnl`
7907    #[serde(rename = "pnl")]
7908    Pnl,
7909    /// `win_rate`
7910    #[serde(rename = "win_rate")]
7911    WinRate,
7912    /// `edge`
7913    #[serde(rename = "edge")]
7914    Edge,
7915    /// A value this release does not know, kept as sent.
7916    #[serde(untagged)]
7917    Other(String),
7918}
7919
7920impl ListLeaderboardSort {
7921    /// The value as the API spells it.
7922    pub fn as_str(&self) -> &str {
7923        match self {
7924            Self::Rank => "rank",
7925            Self::Grade => "grade",
7926            Self::Volume => "volume",
7927            Self::Predictions => "predictions",
7928            Self::Pnl => "pnl",
7929            Self::WinRate => "win_rate",
7930            Self::Edge => "edge",
7931            Self::Other(value) => value,
7932        }
7933    }
7934}
7935
7936impl From<&str> for ListLeaderboardSort {
7937    fn from(value: &str) -> Self {
7938        match value {
7939            "rank" => Self::Rank,
7940            "grade" => Self::Grade,
7941            "volume" => Self::Volume,
7942            "predictions" => Self::Predictions,
7943            "pnl" => Self::Pnl,
7944            "win_rate" => Self::WinRate,
7945            "edge" => Self::Edge,
7946            other => Self::Other(other.to_owned()),
7947        }
7948    }
7949}
7950
7951impl std::fmt::Display for ListLeaderboardSort {
7952    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7953        f.write_str(self.as_str())
7954    }
7955}
7956
7957impl AsRef<str> for ListLeaderboardSort {
7958    fn as_ref(&self) -> &str {
7959        self.as_str()
7960    }
7961}
7962
7963#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7964#[non_exhaustive]
7965pub struct ListPositionsResponse {
7966    pub object: String,
7967    pub data: Vec<Position>,
7968    /// Writer-backed age and coverage for this page; it is part of the representation and the ETag, while transport cache facts remain in meta.
7969    pub data_quality: DataQuality,
7970    pub has_more: bool,
7971    #[serde(default, skip_serializing_if = "Option::is_none")]
7972    pub next_cursor: Option<String>,
7973    /// Total matching rows when the read model exposes a count; the key is absent when it does not.
7974    #[serde(default, skip_serializing_if = "Option::is_none")]
7975    pub total: Option<i64>,
7976    /// Present only with consistency=snapshot. Dates the frozen response rows, not the provider's underlying observations.
7977    #[serde(default, skip_serializing_if = "Option::is_none")]
7978    pub snapshot: Option<ListPositionsResponseSnapshot>,
7979    pub meta: ResponseMeta,
7980}
7981
7982/// Present only with consistency=snapshot. Dates the frozen response rows, not the provider's underlying observations.
7983#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7984#[non_exhaustive]
7985pub struct ListPositionsResponseSnapshot {
7986    pub as_of: String,
7987    pub expires_at: String,
7988    pub row_count: i64,
7989}
7990
7991#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7992#[non_exhaustive]
7993pub struct ListSharpMoneyFlowsResponse {
7994    pub object: String,
7995    pub data: Vec<SmartMoneyFlowMarket>,
7996    pub has_more: bool,
7997    #[serde(default, skip_serializing_if = "Option::is_none")]
7998    pub next_cursor: Option<String>,
7999    #[serde(default, skip_serializing_if = "Option::is_none")]
8000    pub total: Option<i64>,
8001    pub meta: ResponseMeta,
8002}
8003
8004#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8005#[non_exhaustive]
8006pub struct ListSmartMoneyFlowsResponse {
8007    pub object: String,
8008    pub data: Vec<SmartMoneyFlowMarket>,
8009    pub has_more: bool,
8010    #[serde(default, skip_serializing_if = "Option::is_none")]
8011    pub next_cursor: Option<String>,
8012    #[serde(default, skip_serializing_if = "Option::is_none")]
8013    pub total: Option<i64>,
8014    pub meta: ResponseMeta,
8015}
8016
8017#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8018#[non_exhaustive]
8019pub struct ListSuspiciousTradesResponse {
8020    pub object: String,
8021    pub data: Vec<SuspiciousTrade>,
8022    pub has_more: bool,
8023    #[serde(default, skip_serializing_if = "Option::is_none")]
8024    pub next_cursor: Option<String>,
8025    /// Total matching rows when the read model exposes a count; the key is absent when it does not.
8026    #[serde(default, skip_serializing_if = "Option::is_none")]
8027    pub total: Option<i64>,
8028    pub meta: ResponseMeta,
8029}
8030
8031#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8032#[non_exhaustive]
8033pub struct ListTrendingWalletsResponse {
8034    pub object: String,
8035    pub data: Vec<TrendingWallet>,
8036    pub has_more: bool,
8037    /// Opaque cursor for the next page; absent on the last page.
8038    #[serde(default, skip_serializing_if = "Option::is_none")]
8039    pub next_cursor: Option<String>,
8040    /// Total ranked rows when the read model exposes a count; may be absent.
8041    #[serde(default, skip_serializing_if = "Option::is_none")]
8042    pub total: Option<i64>,
8043    pub meta: ResponseMeta,
8044}
8045
8046/// A value this release does not know is kept in `Other`, so a new value never fails a response.
8047#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
8048#[non_exhaustive]
8049pub enum ListTrendingWalletsWindow {
8050    /// `7d`
8051    #[serde(rename = "7d")]
8052    V7d,
8053    /// `30d`
8054    #[serde(rename = "30d")]
8055    V30d,
8056    /// A value this release does not know, kept as sent.
8057    #[serde(untagged)]
8058    Other(String),
8059}
8060
8061impl ListTrendingWalletsWindow {
8062    /// The value as the API spells it.
8063    pub fn as_str(&self) -> &str {
8064        match self {
8065            Self::V7d => "7d",
8066            Self::V30d => "30d",
8067            Self::Other(value) => value,
8068        }
8069    }
8070}
8071
8072impl From<&str> for ListTrendingWalletsWindow {
8073    fn from(value: &str) -> Self {
8074        match value {
8075            "7d" => Self::V7d,
8076            "30d" => Self::V30d,
8077            other => Self::Other(other.to_owned()),
8078        }
8079    }
8080}
8081
8082impl std::fmt::Display for ListTrendingWalletsWindow {
8083    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8084        f.write_str(self.as_str())
8085    }
8086}
8087
8088impl AsRef<str> for ListTrendingWalletsWindow {
8089    fn as_ref(&self) -> &str {
8090        self.as_str()
8091    }
8092}
8093
8094#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8095#[non_exhaustive]
8096pub struct ListWebhookDeliveriesResponse {
8097    pub object: String,
8098    pub data: Vec<WebhookDelivery>,
8099    pub has_more: bool,
8100    #[serde(default, skip_serializing_if = "Option::is_none")]
8101    pub next_cursor: Option<String>,
8102    #[serde(default, skip_serializing_if = "Option::is_none")]
8103    pub total: Option<i64>,
8104    pub meta: ResponseMeta,
8105}
8106
8107#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8108#[non_exhaustive]
8109pub struct ListWebhookEventsResponse {
8110    pub object: String,
8111    pub data: Vec<WebhookEventDescriptor>,
8112    pub has_more: bool,
8113    #[serde(default, skip_serializing_if = "Option::is_none")]
8114    pub next_cursor: Option<String>,
8115    #[serde(default, skip_serializing_if = "Option::is_none")]
8116    pub total: Option<i64>,
8117    pub meta: ResponseMeta,
8118}
8119
8120#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8121#[non_exhaustive]
8122pub struct ListWebhooksResponse {
8123    pub object: String,
8124    pub data: Vec<WebhookEndpoint>,
8125    pub has_more: bool,
8126    #[serde(default, skip_serializing_if = "Option::is_none")]
8127    pub next_cursor: Option<String>,
8128    #[serde(default, skip_serializing_if = "Option::is_none")]
8129    pub total: Option<i64>,
8130    pub meta: ResponseMeta,
8131}
8132
8133#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8134#[non_exhaustive]
8135pub struct ListWhaleTradeCounterpartyExecutionsResponse {
8136    pub object: String,
8137    pub data: CounterpartyAnalysis,
8138    pub meta: ResponseMeta,
8139}
8140
8141#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8142#[non_exhaustive]
8143pub struct ListWhaleTradeCounterpartyMakersResponse {
8144    pub object: String,
8145    pub data: CounterpartyMakerPage,
8146    pub meta: ResponseMeta,
8147}
8148
8149#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8150#[non_exhaustive]
8151pub struct ListWhaleTradeHistoryResponse {
8152    pub object: String,
8153    pub data: Vec<LargeTrade>,
8154    /// Writer-backed age and coverage for this page; it is part of the representation and the ETag, while transport cache facts remain in meta.
8155    pub data_quality: DataQuality,
8156    pub has_more: bool,
8157    #[serde(default, skip_serializing_if = "Option::is_none")]
8158    pub next_cursor: Option<String>,
8159    /// Total matching rows when the read model exposes a count; absent (or null) when it does not.
8160    #[serde(default, skip_serializing_if = "Option::is_none")]
8161    pub total: Option<i64>,
8162    pub meta: LargeTradeHistoryMeta,
8163}
8164
8165#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8166#[non_exhaustive]
8167pub struct ListWhaleTradesResponse {
8168    pub object: String,
8169    pub data: Vec<LargeTrade>,
8170    /// Writer-backed age and coverage for this page; it is part of the representation and the ETag, while transport cache facts remain in meta.
8171    pub data_quality: DataQuality,
8172    pub has_more: bool,
8173    #[serde(default, skip_serializing_if = "Option::is_none")]
8174    pub next_cursor: Option<String>,
8175    /// Total matching rows when the read model exposes a count; the key is absent when it does not.
8176    #[serde(default, skip_serializing_if = "Option::is_none")]
8177    pub total: Option<i64>,
8178    pub meta: ResponseMeta,
8179}
8180
8181/// One side's score line inside a `live_sports_updated` pulse.
8182#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8183#[non_exhaustive]
8184pub struct LiveSportsScoreEntry {
8185    /// Team name, ordered for the league (away first where the league reads that way).
8186    pub team: String,
8187    /// This side's score as the provider sends it.
8188    pub score: String,
8189    /// Esports series only: this side's current-map score. Absent on other sports.
8190    #[serde(default, skip_serializing_if = "Option::is_none")]
8191    pub map_score: Option<String>,
8192}
8193
8194/// `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.
8195#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8196#[non_exhaustive]
8197pub struct LiveSportsUpdatedData {
8198    /// The Polymarket event slug this game trades under.
8199    pub event_slug: String,
8200    /// Provider game id, or `null` when the frame carried none.
8201    #[serde(default)]
8202    pub game_id: Option<String>,
8203    /// League abbreviation, or `null`.
8204    #[serde(default)]
8205    pub league: Option<String>,
8206    /// Durable per-game pulse ordinal, increasing by one per delivered pulse. Deliveries are not ordered, so drop a pulse whose version you already saw.
8207    pub version: i64,
8208    /// Material fields that moved since this game's previous delivered pulse.
8209    pub changed: Vec<Changed>,
8210    /// Provider frame time, or `null` when the frame carried none. Never replaced with a local clock.
8211    #[serde(default)]
8212    pub observed_at: Option<String>,
8213    /// When the pulse was admitted.
8214    pub published_at: String,
8215    /// Provider status text, or `null`.
8216    #[serde(default)]
8217    pub status: Option<String>,
8218    /// Provider period text ("Q3", "Map 2/3"), or `null`.
8219    #[serde(default)]
8220    pub period: Option<String>,
8221    /// Game clock, or `null`. Not a material field: it never fires a pulse on its own.
8222    #[serde(default)]
8223    pub clock: Option<String>,
8224    /// Provider live flag, or `null` when the frame carried none.
8225    #[serde(default)]
8226    pub live: Option<bool>,
8227    /// Whether the provider has marked this game final.
8228    pub ended: bool,
8229    /// Per-side scores, one line per team.
8230    pub scores: Vec<LiveSportsScoreEntry>,
8231    /// Esports `BoN` series token, or `null` on every other sport.
8232    #[serde(default)]
8233    pub series_format: Option<String>,
8234    /// Public game page. Re-read it after a gap instead of replaying pulses.
8235    pub snapshot_url: String,
8236}
8237
8238/// 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).
8239#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8240#[non_exhaustive]
8241pub struct MarketCandles {
8242    /// Market condition id the candles were read for.
8243    pub condition_id: String,
8244    /// Bucketing granularity that produced these candles.
8245    pub resolution: Resolution,
8246    /// One entry per present provider token (YES first, then NO); empty when no tokens have been fetched yet.
8247    pub outcomes: Vec<OutcomeCandles>,
8248}
8249
8250#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8251#[non_exhaustive]
8252pub struct MarketFlow {
8253    pub market: MarketFlowMarket,
8254    /// 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.
8255    pub sharp_money: MarketFlowSharpMoney,
8256    /// Deprecated alias of sharp_money; byte-identical. Sunset 2027-02-01 (#29352): removed from V1 on that date; read sharp_money.
8257    pub smart_money: MarketFlowSmartMoney,
8258    pub timeframe: String,
8259}
8260
8261#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8262#[non_exhaustive]
8263pub struct MarketFlowMarket {
8264    pub id: String,
8265    pub condition_id: String,
8266    pub title: String,
8267    #[serde(default)]
8268    pub slug: Option<String>,
8269    #[serde(default)]
8270    pub category: Option<String>,
8271    /// Provider platform. Always polymarket, or null when the row carries no stored value.
8272    #[serde(default)]
8273    pub platform: Option<String>,
8274}
8275
8276/// 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.
8277#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8278#[non_exhaustive]
8279pub struct MarketFlowSharpMoney {
8280    pub net_flow_usd: f64,
8281    pub direction: Direction,
8282    /// The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets).
8283    #[serde(default)]
8284    pub token_id: Option<String>,
8285    /// 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).
8286    pub large_trade_count: i64,
8287    /// 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.
8288    pub whale_trade_count: i64,
8289    pub buy_volume_usd: f64,
8290    pub sell_volume_usd: f64,
8291    pub top_positions: Vec<MarketFlowSharpMoneyTopPositionsItem>,
8292    /// 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.
8293    #[serde(default)]
8294    pub oldest_snapshot_as_of: Option<String>,
8295}
8296
8297#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8298#[non_exhaustive]
8299pub struct MarketFlowSharpMoneyTopPositionsItem {
8300    pub id: String,
8301    pub address: String,
8302    #[serde(default)]
8303    pub username: Option<String>,
8304    #[serde(default)]
8305    pub grade: Option<Grade>,
8306    pub side: Direction,
8307    /// The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets).
8308    #[serde(default)]
8309    pub token_id: Option<String>,
8310    pub size_usd: f64,
8311}
8312
8313/// Deprecated alias of sharp_money; byte-identical. Sunset 2027-02-01 (#29352): removed from V1 on that date; read sharp_money.
8314#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8315#[non_exhaustive]
8316pub struct MarketFlowSmartMoney {
8317    pub net_flow_usd: f64,
8318    pub direction: Direction,
8319    /// The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets).
8320    #[serde(default)]
8321    pub token_id: Option<String>,
8322    /// 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).
8323    pub large_trade_count: i64,
8324    /// 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.
8325    pub whale_trade_count: i64,
8326    pub buy_volume_usd: f64,
8327    pub sell_volume_usd: f64,
8328    pub top_positions: Vec<MarketFlowSmartMoneyTopPositionsItem>,
8329    /// 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.
8330    #[serde(default)]
8331    pub oldest_snapshot_as_of: Option<String>,
8332}
8333
8334#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8335#[non_exhaustive]
8336pub struct MarketFlowSmartMoneyTopPositionsItem {
8337    pub id: String,
8338    pub address: String,
8339    #[serde(default)]
8340    pub username: Option<String>,
8341    #[serde(default)]
8342    pub grade: Option<Grade>,
8343    pub side: Direction,
8344    /// The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets).
8345    #[serde(default)]
8346    pub token_id: Option<String>,
8347    pub size_usd: f64,
8348}
8349
8350#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8351#[non_exhaustive]
8352pub struct MarketHolder {
8353    /// Composite `pos_<wallet>:<condition_id>:<outcome_index>`, the same id `GET /api/v1/positions` gives this leg.
8354    pub id: String,
8355    /// `trd_`-prefixed trader id, accepted by `GET /api/v1/trader/{address}`.
8356    pub trader_id: String,
8357    /// Lowercased proxy wallet.
8358    pub address: String,
8359    /// Polymarket's public display name from the same holder snapshot; null for a private wallet, which the provider redacts at the source.
8360    #[serde(default)]
8361    pub name: Option<String>,
8362    /// The outcome this wallet nets to. A wallet holding both outcomes is listed once, on its net side; see `other_outcome_shares`.
8363    pub side: Direction,
8364    /// Polymarket CLOB token id (ERC1155 asset id, decimal string) for `side`; null when the market has no stored token id.
8365    #[serde(default)]
8366    pub token_id: Option<String>,
8367    /// All-time trader grade. This route lists the S/A/B cohort only, the same cohort a Pick of the Day roster lists.
8368    #[serde(default)]
8369    pub grade: Option<MarketHolderGrade>,
8370    /// Shares held on `side`, from the complete provider scan.
8371    pub shares: f64,
8372    /// Polymarket's own currentValue for this leg, in USD. Null when the snapshot predates the value map.
8373    #[serde(default)]
8374    pub current_value_usd: Option<f64>,
8375    /// Shares on the other outcome when the wallet holds both. Absent when the wallet is one-sided.
8376    #[serde(default, skip_serializing_if = "Option::is_none")]
8377    pub other_outcome_shares: Option<f64>,
8378    /// The wallet's last recorded trade anywhere, null when unknown.
8379    #[serde(default)]
8380    pub last_traded_at: Option<String>,
8381    /// 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.
8382    #[serde(default, skip_serializing_if = "Option::is_none")]
8383    pub category_win_rate: Option<f64>,
8384    /// 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`.
8385    #[serde(default, skip_serializing_if = "Option::is_none")]
8386    pub category_win_record: Option<MarketHolderCategoryWinRecord>,
8387    /// 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.
8388    #[serde(default, skip_serializing_if = "Option::is_none")]
8389    pub category_avg_price: Option<f64>,
8390    /// 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.
8391    #[serde(default, skip_serializing_if = "Option::is_none")]
8392    pub category_win_rate_game: Option<String>,
8393    /// 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.
8394    pub category_win_rate_status: CategoryWinRateStatus,
8395    #[serde(default, skip_serializing_if = "Option::is_none")]
8396    pub category_evidence: Option<HolderCategoryEvidence>,
8397    /// 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.
8398    #[serde(default, skip_serializing_if = "Option::is_none")]
8399    pub wallet_age_days: Option<f64>,
8400    /// True when the wallet's first trade was under 30 days ago.
8401    #[serde(default, skip_serializing_if = "Option::is_none")]
8402    pub is_new_wallet: Option<bool>,
8403    /// Distinct markets the wallet has traded.
8404    #[serde(default, skip_serializing_if = "Option::is_none")]
8405    pub markets_traded: Option<i64>,
8406    /// True when the wallet is flagged as automated.
8407    #[serde(default, skip_serializing_if = "Option::is_none")]
8408    pub is_bot: Option<bool>,
8409    /// The wallet's X handle without the @, when linked.
8410    #[serde(default, skip_serializing_if = "Option::is_none")]
8411    pub x_username: Option<String>,
8412}
8413
8414/// 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`.
8415#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8416#[non_exhaustive]
8417pub struct MarketHolderCategoryWinRecord {
8418    /// Settled markets in the category that this wallet closed with a profit.
8419    pub wins: i64,
8420    /// 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.
8421    pub decided: i64,
8422}
8423
8424/// A value this release does not know is kept in `Other`, so a new value never fails a response.
8425#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
8426#[non_exhaustive]
8427pub enum MarketHolderGrade {
8428    /// `S`
8429    #[serde(rename = "S")]
8430    S,
8431    /// `A`
8432    #[serde(rename = "A")]
8433    A,
8434    /// `B`
8435    #[serde(rename = "B")]
8436    B,
8437    /// A value this release does not know, kept as sent.
8438    #[serde(untagged)]
8439    Other(String),
8440}
8441
8442impl MarketHolderGrade {
8443    /// The value as the API spells it.
8444    pub fn as_str(&self) -> &str {
8445        match self {
8446            Self::S => "S",
8447            Self::A => "A",
8448            Self::B => "B",
8449            Self::Other(value) => value,
8450        }
8451    }
8452}
8453
8454impl From<&str> for MarketHolderGrade {
8455    fn from(value: &str) -> Self {
8456        match value {
8457            "S" => Self::S,
8458            "A" => Self::A,
8459            "B" => Self::B,
8460            other => Self::Other(other.to_owned()),
8461        }
8462    }
8463}
8464
8465impl std::fmt::Display for MarketHolderGrade {
8466    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8467        f.write_str(self.as_str())
8468    }
8469}
8470
8471impl AsRef<str> for MarketHolderGrade {
8472    fn as_ref(&self) -> &str {
8473        self.as_str()
8474    }
8475}
8476
8477#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8478#[non_exhaustive]
8479pub struct MarketHoldersMarket {
8480    /// `mkt_`-prefixed market id.
8481    pub id: String,
8482    pub condition_id: String,
8483    #[serde(default)]
8484    pub title: Option<String>,
8485    #[serde(default, skip_serializing_if = "Option::is_none")]
8486    pub slug: Option<String>,
8487    #[serde(default, skip_serializing_if = "Option::is_none")]
8488    pub event_slug: Option<String>,
8489    /// The canonical category bucket `category_win_rate` is measured in.
8490    #[serde(default)]
8491    pub category: Option<String>,
8492    #[serde(default)]
8493    pub outcome_yes: Option<String>,
8494    #[serde(default)]
8495    pub outcome_no: Option<String>,
8496    #[serde(default)]
8497    pub token_id_yes: Option<String>,
8498    #[serde(default)]
8499    pub token_id_no: Option<String>,
8500    #[serde(default, skip_serializing_if = "Option::is_none")]
8501    pub end_date: Option<String>,
8502    /// A settled market's roster is whatever the provider still lists as open; it empties as holders redeem.
8503    pub status: MarketHoldersMarketStatus,
8504}
8505
8506/// A value this release does not know is kept in `Other`, so a new value never fails a response.
8507#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
8508#[non_exhaustive]
8509pub enum MarketHoldersMarketStatus {
8510    /// `open`
8511    #[serde(rename = "open")]
8512    Open,
8513    /// `closed`
8514    #[serde(rename = "closed")]
8515    Closed,
8516    /// `resolved`
8517    #[serde(rename = "resolved")]
8518    Resolved,
8519    /// A value this release does not know, kept as sent.
8520    #[serde(untagged)]
8521    Other(String),
8522}
8523
8524impl MarketHoldersMarketStatus {
8525    /// The value as the API spells it.
8526    pub fn as_str(&self) -> &str {
8527        match self {
8528            Self::Open => "open",
8529            Self::Closed => "closed",
8530            Self::Resolved => "resolved",
8531            Self::Other(value) => value,
8532        }
8533    }
8534}
8535
8536impl From<&str> for MarketHoldersMarketStatus {
8537    fn from(value: &str) -> Self {
8538        match value {
8539            "open" => Self::Open,
8540            "closed" => Self::Closed,
8541            "resolved" => Self::Resolved,
8542            other => Self::Other(other.to_owned()),
8543        }
8544    }
8545}
8546
8547impl std::fmt::Display for MarketHoldersMarketStatus {
8548    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8549        f.write_str(self.as_str())
8550    }
8551}
8552
8553impl AsRef<str> for MarketHoldersMarketStatus {
8554    fn as_ref(&self) -> &str {
8555        self.as_str()
8556    }
8557}
8558
8559#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8560#[non_exhaustive]
8561pub struct MarketHoldersScan {
8562    /// `cached`: the shared holder snapshot, at most 180 s old at compute time. `live`: the provider answered a fresh complete walk for this compute.
8563    pub source: ProviderReadSource,
8564    /// Always true on a served roster. An incomplete or unstable scan is a 503, never a partial list.
8565    pub complete: bool,
8566    /// When the provider walk that produced the holder population finished.
8567    #[serde(default)]
8568    pub fetched_at: Option<String>,
8569    /// Every distinct wallet the complete walk saw with open shares, graded or not. The roster lists the graded S/A/B subset.
8570    pub wallet_count: i64,
8571}
8572
8573/// 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.
8574#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8575#[non_exhaustive]
8576pub struct MarketHoldersSideGradeUsd {
8577    /// USD held by S-grade wallets netting this side.
8578    pub s: f64,
8579    /// USD held by A-grade wallets netting this side.
8580    pub a: f64,
8581    /// USD held by B-grade wallets netting this side.
8582    pub b: f64,
8583}
8584
8585#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8586#[non_exhaustive]
8587pub struct MarketHoldersSideGrades {
8588    pub s: i64,
8589    pub a: i64,
8590    pub b: i64,
8591}
8592
8593/// Roster totals BEFORE any `outcome` or `min_grade` filter, so a page always knows the whole market it was cut from.
8594#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8595#[non_exhaustive]
8596pub struct MarketHoldersTotals {
8597    /// Distinct graded wallets with net exposure; a two-sided wallet counts once.
8598    pub graded_count: i64,
8599    pub yes_count: i64,
8600    pub no_count: i64,
8601    pub yes_shares: f64,
8602    pub no_shares: f64,
8603    /// Polymarket currentValue summed over the graded wallets netting YES.
8604    pub yes_usd: f64,
8605    /// Polymarket currentValue summed over the graded wallets netting NO.
8606    pub no_usd: f64,
8607    pub yes_grades: MarketHoldersSideGrades,
8608    pub no_grades: MarketHoldersSideGrades,
8609    /// yes_usd split by grade: where the S, A and B money on YES sits.
8610    pub yes_grade_usd: MarketHoldersSideGradeUsd,
8611    /// no_usd split by grade: where the S, A and B money on NO sits.
8612    pub no_grade_usd: MarketHoldersSideGradeUsd,
8613}
8614
8615/// A value this release does not know is kept in `Other`, so a new value never fails a response.
8616#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
8617#[non_exhaustive]
8618pub enum MarketScope {
8619    /// `all_markets`
8620    #[serde(rename = "all_markets")]
8621    AllMarkets,
8622    /// `sports_and_esports`
8623    #[serde(rename = "sports_and_esports")]
8624    SportsAndEsports,
8625    /// A value this release does not know, kept as sent.
8626    #[serde(untagged)]
8627    Other(String),
8628}
8629
8630impl MarketScope {
8631    /// The value as the API spells it.
8632    pub fn as_str(&self) -> &str {
8633        match self {
8634            Self::AllMarkets => "all_markets",
8635            Self::SportsAndEsports => "sports_and_esports",
8636            Self::Other(value) => value,
8637        }
8638    }
8639}
8640
8641impl From<&str> for MarketScope {
8642    fn from(value: &str) -> Self {
8643        match value {
8644            "all_markets" => Self::AllMarkets,
8645            "sports_and_esports" => Self::SportsAndEsports,
8646            other => Self::Other(other.to_owned()),
8647        }
8648    }
8649}
8650
8651impl std::fmt::Display for MarketScope {
8652    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8653        f.write_str(self.as_str())
8654    }
8655}
8656
8657impl AsRef<str> for MarketScope {
8658    fn as_ref(&self) -> &str {
8659        self.as_str()
8660    }
8661}
8662
8663#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8664#[non_exhaustive]
8665pub struct MarketSearchResult {
8666    pub id: String,
8667    pub condition_id: String,
8668    pub title: String,
8669    #[serde(default)]
8670    pub slug: Option<String>,
8671    #[serde(default)]
8672    pub category: Option<String>,
8673    /// Provider platform. Always polymarket, or null when the row carries no stored value.
8674    #[serde(default)]
8675    pub platform: Option<String>,
8676    /// 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.
8677    pub status: MarketSearchResultStatus,
8678    #[serde(default, skip_serializing_if = "Option::is_none")]
8679    pub event_slug: Option<String>,
8680}
8681
8682/// A value this release does not know is kept in `Other`, so a new value never fails a response.
8683#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
8684#[non_exhaustive]
8685pub enum MarketSearchResultStatus {
8686    /// `active`
8687    #[serde(rename = "active")]
8688    Active,
8689    /// `closed`
8690    #[serde(rename = "closed")]
8691    Closed,
8692    /// A value this release does not know, kept as sent.
8693    #[serde(untagged)]
8694    Other(String),
8695}
8696
8697impl MarketSearchResultStatus {
8698    /// The value as the API spells it.
8699    pub fn as_str(&self) -> &str {
8700        match self {
8701            Self::Active => "active",
8702            Self::Closed => "closed",
8703            Self::Other(value) => value,
8704        }
8705    }
8706}
8707
8708impl From<&str> for MarketSearchResultStatus {
8709    fn from(value: &str) -> Self {
8710        match value {
8711            "active" => Self::Active,
8712            "closed" => Self::Closed,
8713            other => Self::Other(other.to_owned()),
8714        }
8715    }
8716}
8717
8718impl std::fmt::Display for MarketSearchResultStatus {
8719    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8720        f.write_str(self.as_str())
8721    }
8722}
8723
8724impl AsRef<str> for MarketSearchResultStatus {
8725    fn as_ref(&self) -> &str {
8726        self.as_str()
8727    }
8728}
8729
8730#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8731#[non_exhaustive]
8732pub struct MarketSnapshot {
8733    pub market: MarketSnapshotMarket,
8734    pub outcomes: Vec<MarketSnapshotOutcomesItem>,
8735    pub liquidity: MarketSnapshotLiquidity,
8736    pub sports: MarketSnapshotSports,
8737    pub freshness: MarketSnapshotFreshnessBySource,
8738    /// Price and spread trust metadata. Present only when expand=trust or expand[]=trust is requested.
8739    #[serde(default, skip_serializing_if = "Option::is_none")]
8740    pub trust: Option<MarketSnapshotTrust>,
8741}
8742
8743#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8744#[non_exhaustive]
8745pub struct MarketSnapshotFreshness {
8746    pub status: MarketSnapshotFreshnessStatus,
8747    pub source: String,
8748    #[serde(default, skip_serializing_if = "Option::is_none")]
8749    pub as_of: Option<String>,
8750    /// 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.
8751    #[serde(default, skip_serializing_if = "Option::is_none")]
8752    pub stale_after_s: Option<i64>,
8753    #[serde(default, skip_serializing_if = "Option::is_none")]
8754    pub reason: Option<String>,
8755}
8756
8757#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8758#[non_exhaustive]
8759pub struct MarketSnapshotFreshnessBySource {
8760    pub market_data: MarketSnapshotFreshness,
8761    pub top_of_book: MarketSnapshotFreshness,
8762    /// 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.
8763    pub live_sports: MarketSnapshotFreshness,
8764}
8765
8766/// A value this release does not know is kept in `Other`, so a new value never fails a response.
8767#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
8768#[non_exhaustive]
8769pub enum MarketSnapshotFreshnessStatus {
8770    /// `fresh`
8771    #[serde(rename = "fresh")]
8772    Fresh,
8773    /// `stale`
8774    #[serde(rename = "stale")]
8775    Stale,
8776    /// `available`
8777    #[serde(rename = "available")]
8778    Available,
8779    /// `not_live`
8780    #[serde(rename = "not_live")]
8781    NotLive,
8782    /// `unavailable`
8783    #[serde(rename = "unavailable")]
8784    Unavailable,
8785    /// A value this release does not know, kept as sent.
8786    #[serde(untagged)]
8787    Other(String),
8788}
8789
8790impl MarketSnapshotFreshnessStatus {
8791    /// The value as the API spells it.
8792    pub fn as_str(&self) -> &str {
8793        match self {
8794            Self::Fresh => "fresh",
8795            Self::Stale => "stale",
8796            Self::Available => "available",
8797            Self::NotLive => "not_live",
8798            Self::Unavailable => "unavailable",
8799            Self::Other(value) => value,
8800        }
8801    }
8802}
8803
8804impl From<&str> for MarketSnapshotFreshnessStatus {
8805    fn from(value: &str) -> Self {
8806        match value {
8807            "fresh" => Self::Fresh,
8808            "stale" => Self::Stale,
8809            "available" => Self::Available,
8810            "not_live" => Self::NotLive,
8811            "unavailable" => Self::Unavailable,
8812            other => Self::Other(other.to_owned()),
8813        }
8814    }
8815}
8816
8817impl std::fmt::Display for MarketSnapshotFreshnessStatus {
8818    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8819        f.write_str(self.as_str())
8820    }
8821}
8822
8823impl AsRef<str> for MarketSnapshotFreshnessStatus {
8824    fn as_ref(&self) -> &str {
8825        self.as_str()
8826    }
8827}
8828
8829#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8830#[non_exhaustive]
8831pub struct MarketSnapshotLiquidity {
8832    pub source: String,
8833    /// 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.
8834    #[serde(default)]
8835    pub volume_usd: Option<f64>,
8836    #[serde(default)]
8837    pub liquidity_usd: Option<f64>,
8838    /// 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.
8839    #[serde(default)]
8840    pub volume_24h_usd: Option<f64>,
8841    /// 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.
8842    #[serde(default)]
8843    pub volume_24h_as_of: Option<String>,
8844    /// Always null. Polymarket snapshot prices come from outcome top-of-book midpoints.
8845    #[serde(default)]
8846    pub last_price: Option<f64>,
8847}
8848
8849#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8850#[non_exhaustive]
8851pub struct MarketSnapshotMarket {
8852    pub id: String,
8853    pub condition_id: String,
8854    pub provider: String,
8855    #[serde(default)]
8856    pub title: Option<String>,
8857    #[serde(default)]
8858    pub slug: Option<String>,
8859    #[serde(default)]
8860    pub page_slug: Option<String>,
8861    #[serde(default)]
8862    pub event_slug: Option<String>,
8863    #[serde(default)]
8864    pub category: Option<String>,
8865    /// 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.
8866    pub status: MarketSearchResultStatus,
8867    #[serde(default)]
8868    pub description: Option<String>,
8869    #[serde(default)]
8870    pub image: Option<String>,
8871    /// 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.
8872    #[serde(default)]
8873    pub series_slug: Option<String>,
8874    /// 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.
8875    #[serde(default)]
8876    pub market_type: Option<String>,
8877    /// 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.
8878    #[serde(default)]
8879    pub market_result: Option<String>,
8880    #[serde(default)]
8881    pub created_at: Option<String>,
8882    #[serde(default)]
8883    pub end_date: Option<String>,
8884    #[serde(default)]
8885    pub resolved_at: Option<String>,
8886}
8887
8888#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8889#[non_exhaustive]
8890pub struct MarketSnapshotOutcomesItem {
8891    pub side: SuspiciousTradeFlaggedDataSide,
8892    pub label: String,
8893    #[serde(default, skip_serializing_if = "Option::is_none")]
8894    pub token_id: Option<String>,
8895    /// 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.
8896    #[serde(default, skip_serializing_if = "Option::is_none")]
8897    pub current_price: Option<f64>,
8898    pub top_of_book: MarketSnapshotTopOfBook,
8899}
8900
8901#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8902#[non_exhaustive]
8903pub struct MarketSnapshotSports {
8904    pub status: MarketSnapshotSportsStatus,
8905    pub source: String,
8906    #[serde(default, skip_serializing_if = "Option::is_none")]
8907    pub live_match_key: Option<String>,
8908    #[serde(default, skip_serializing_if = "Option::is_none")]
8909    pub live_league_key: Option<String>,
8910    /// Live-score period and elapsed may be omitted when unavailable (older responses use null). A score entry may omit full_name when it equals team; fall back to team. Distinct aliases and score admission markers are preserved. 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.
8911    #[serde(default, skip_serializing_if = "Option::is_none")]
8912    pub live_score: Option<MarketSnapshotSportsLiveScore>,
8913    #[serde(default, skip_serializing_if = "Option::is_none")]
8914    pub reason: Option<String>,
8915}
8916
8917/// Live-score period and elapsed may be omitted when unavailable (older responses use null). A score entry may omit full_name when it equals team; fall back to team. Distinct aliases and score admission markers are preserved. 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.
8918#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8919#[non_exhaustive]
8920pub struct MarketSnapshotSportsLiveScore {
8921    #[serde(default, skip_serializing_if = "Option::is_none")]
8922    pub tennis_points: Option<TennisPoints>,
8923}
8924
8925/// A value this release does not know is kept in `Other`, so a new value never fails a response.
8926#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
8927#[non_exhaustive]
8928pub enum MarketSnapshotSportsStatus {
8929    /// `fresh`
8930    #[serde(rename = "fresh")]
8931    Fresh,
8932    /// `stale`
8933    #[serde(rename = "stale")]
8934    Stale,
8935    /// `not_live`
8936    #[serde(rename = "not_live")]
8937    NotLive,
8938    /// `unavailable`
8939    #[serde(rename = "unavailable")]
8940    Unavailable,
8941    /// A value this release does not know, kept as sent.
8942    #[serde(untagged)]
8943    Other(String),
8944}
8945
8946impl MarketSnapshotSportsStatus {
8947    /// The value as the API spells it.
8948    pub fn as_str(&self) -> &str {
8949        match self {
8950            Self::Fresh => "fresh",
8951            Self::Stale => "stale",
8952            Self::NotLive => "not_live",
8953            Self::Unavailable => "unavailable",
8954            Self::Other(value) => value,
8955        }
8956    }
8957}
8958
8959impl From<&str> for MarketSnapshotSportsStatus {
8960    fn from(value: &str) -> Self {
8961        match value {
8962            "fresh" => Self::Fresh,
8963            "stale" => Self::Stale,
8964            "not_live" => Self::NotLive,
8965            "unavailable" => Self::Unavailable,
8966            other => Self::Other(other.to_owned()),
8967        }
8968    }
8969}
8970
8971impl std::fmt::Display for MarketSnapshotSportsStatus {
8972    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8973        f.write_str(self.as_str())
8974    }
8975}
8976
8977impl AsRef<str> for MarketSnapshotSportsStatus {
8978    fn as_ref(&self) -> &str {
8979        self.as_str()
8980    }
8981}
8982
8983#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8984#[non_exhaustive]
8985pub struct MarketSnapshotTopOfBook {
8986    pub status: EnrichmentStatus,
8987    pub source: String,
8988    #[serde(default, skip_serializing_if = "Option::is_none")]
8989    pub best_bid: Option<f64>,
8990    #[serde(default, skip_serializing_if = "Option::is_none")]
8991    pub best_ask: Option<f64>,
8992    #[serde(default, skip_serializing_if = "Option::is_none")]
8993    pub spread_bps: Option<i64>,
8994    #[serde(default, skip_serializing_if = "Option::is_none")]
8995    pub bid_depth_usdc: Option<f64>,
8996    #[serde(default, skip_serializing_if = "Option::is_none")]
8997    pub ask_depth_usdc: Option<f64>,
8998    #[serde(default, skip_serializing_if = "Option::is_none")]
8999    pub reason: Option<String>,
9000}
9001
9002/// Price and spread trust metadata returned only when GET /api/v1/market/{condition_id}/snapshot includes expand=trust.
9003#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9004#[non_exhaustive]
9005pub struct MarketSnapshotTrust {
9006    pub current_price: TrustMetadata,
9007    pub spread_bps: TrustMetadata,
9008}
9009
9010#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9011#[non_exhaustive]
9012pub struct MarketTopHolder {
9013    /// 1-based position on this outcome, by shares.
9014    pub rank: i64,
9015    /// `trd_`-prefixed trader id, accepted by `GET /api/v1/trader/{address}`.
9016    pub trader_id: String,
9017    /// Lowercased proxy wallet.
9018    pub address: String,
9019    /// The wallet's display name; null when it shows none.
9020    #[serde(default)]
9021    pub name: Option<String>,
9022    /// All-time trader grade, S to F. Null for a wallet 0xinsider has not graded: this route lists every holder whatever its grade.
9023    #[serde(default)]
9024    pub grade: Option<Grade>,
9025    /// Shares held on this outcome.
9026    pub shares: f64,
9027    /// Polymarket's current value of this position, in USD. Null when the provider served none.
9028    #[serde(default)]
9029    pub current_value_usd: Option<f64>,
9030    /// Average price paid for the shares still held, as a 0..1 fraction of $1. Null when the provider served none.
9031    #[serde(default)]
9032    pub avg_entry_price: Option<f64>,
9033    /// Shares on the other outcome when the wallet holds both; the wallet is then listed on both sides. Absent when it is one-sided.
9034    #[serde(default, skip_serializing_if = "Option::is_none")]
9035    pub other_outcome_shares: Option<f64>,
9036    /// Polymarket's realized P&L of this position (sells and redemptions), in USD. Null when the provider served no economics for the row.
9037    #[serde(default)]
9038    pub position_realized_pnl: Option<f64>,
9039    /// Polymarket's mark-to-market P&L of the shares still held, in USD. On a resolved market the mark is the settlement price.
9040    #[serde(default)]
9041    pub position_unrealized_pnl: Option<f64>,
9042    /// `position_realized_pnl` plus `position_unrealized_pnl`, in USD.
9043    #[serde(default)]
9044    pub position_total_pnl: Option<f64>,
9045    /// 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`.
9046    #[serde(default)]
9047    pub in_scope_realized_pnl: Option<f64>,
9048    /// The wallet's volume traded on sports and esports markets, in USD. Null under the same rule as `in_scope_realized_pnl`.
9049    #[serde(default)]
9050    pub in_scope_volume: Option<f64>,
9051    /// The wallet's stored trading-style label (see Wallet trading styles); null when it has none.
9052    #[serde(default)]
9053    pub strategy_type: Option<String>,
9054    /// The wallet's last recorded trade anywhere, null when unknown.
9055    #[serde(default)]
9056    pub last_traded_at: Option<String>,
9057    /// 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.
9058    #[serde(default, skip_serializing_if = "Option::is_none")]
9059    pub category_win_rate: Option<f64>,
9060    /// 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`.
9061    #[serde(default, skip_serializing_if = "Option::is_none")]
9062    pub category_win_record: Option<MarketTopHolderCategoryWinRecord>,
9063    /// 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.
9064    #[serde(default, skip_serializing_if = "Option::is_none")]
9065    pub category_avg_price: Option<f64>,
9066    /// 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.
9067    #[serde(default, skip_serializing_if = "Option::is_none")]
9068    pub category_win_rate_game: Option<String>,
9069    /// 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.
9070    #[serde(default, skip_serializing_if = "Option::is_none")]
9071    pub category_win_rate_status: Option<CategoryWinRateStatus>,
9072    /// 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.
9073    #[serde(default, skip_serializing_if = "Option::is_none")]
9074    pub wallet_age_days: Option<f64>,
9075    /// True when the wallet's first trade was under 30 days ago.
9076    #[serde(default, skip_serializing_if = "Option::is_none")]
9077    pub is_new_wallet: Option<bool>,
9078    /// Distinct markets the wallet has traded.
9079    #[serde(default, skip_serializing_if = "Option::is_none")]
9080    pub markets_traded: Option<i64>,
9081    /// True when the wallet is flagged as automated.
9082    #[serde(default, skip_serializing_if = "Option::is_none")]
9083    pub is_bot: Option<bool>,
9084    /// The wallet's X handle without the @, when linked.
9085    #[serde(default, skip_serializing_if = "Option::is_none")]
9086    pub x_username: Option<String>,
9087}
9088
9089/// 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`.
9090#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9091#[non_exhaustive]
9092pub struct MarketTopHolderCategoryWinRecord {
9093    /// Settled markets in the category that this wallet closed with a profit.
9094    pub wins: i64,
9095    /// 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.
9096    pub decided: i64,
9097}
9098
9099#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9100#[non_exhaustive]
9101pub struct MarketTopHolders {
9102    pub market: MarketHoldersMarket,
9103    /// The largest YES holders, by shares, up to `limit`.
9104    pub yes: Vec<MarketTopHolder>,
9105    /// The largest NO holders, by shares, up to `limit`.
9106    pub no: Vec<MarketTopHolder>,
9107    pub totals: MarketTopHoldersTotals,
9108    /// `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.
9109    pub profiles_status: EnrichmentStatus,
9110    /// When the daily pass behind the rows' category win records began. Absent when the market has no category or the read answered no row.
9111    #[serde(default, skip_serializing_if = "Option::is_none")]
9112    pub category_records_as_of: Option<String>,
9113    /// When this holder sample was built.
9114    #[serde(default, skip_serializing_if = "Option::is_none")]
9115    pub computed_at: Option<String>,
9116    /// 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.
9117    #[serde(default, skip_serializing_if = "Option::is_none")]
9118    pub positions_as_of: Option<String>,
9119    /// `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.
9120    pub source_stale: bool,
9121}
9122
9123#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9124#[non_exhaustive]
9125pub struct MarketTopHoldersTotals {
9126    /// Holders in the YES sample, before `limit`. Equal to `sample_cap` means that many or more.
9127    pub yes_count: i64,
9128    /// Holders in the NO sample, before `limit`.
9129    pub no_count: i64,
9130    /// Shares summed over the YES sample.
9131    pub yes_shares: f64,
9132    /// Shares summed over the NO sample.
9133    pub no_shares: f64,
9134    /// The most holders the sample keeps per outcome (100).
9135    pub sample_cap: i64,
9136}
9137
9138/// 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.
9139#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9140#[non_exhaustive]
9141pub struct MarketWalletsInOut {
9142    /// The market's raw provider condition id.
9143    pub condition_id: String,
9144    /// The window the nets are summed over: 24h or 7d.
9145    pub window: String,
9146    /// The window's inclusive start; null only when the bounds are unknown.
9147    #[serde(default)]
9148    pub window_start: Option<String>,
9149    /// The window's inclusive end, the read's clock; null only when the bounds are unknown.
9150    #[serde(default)]
9151    pub window_end: Option<String>,
9152    /// Totals over every wallet that traded the market in the window, not only the listed 50.
9153    pub summary: MarketWalletsInOutSummary,
9154    /// Wallets whose net is positive, largest first, at most 25.
9155    pub net_buyers: Vec<MarketWalletsInOutNetBuyersItem>,
9156    /// Wallets whose net is negative, most negative first, at most 25.
9157    pub net_sellers: Vec<MarketWalletsInOutNetSellersItem>,
9158}
9159
9160/// One wallet's net in the window.
9161#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9162#[non_exhaustive]
9163pub struct MarketWalletsInOutNetBuyersItem {
9164    /// Lowercase proxy wallet.
9165    pub address: String,
9166    /// The name the site shows: the 0xinsider username, else the shortened address.
9167    pub display_name: String,
9168    /// Today's grade; null for an ungraded or untracked wallet.
9169    #[serde(default)]
9170    pub grade: Option<Grade>,
9171    /// Buys minus sells in the window, both outcomes, in USD: the matched notional, fees excluded.
9172    pub net_usd: f64,
9173    /// Fills in the window.
9174    pub trades: i64,
9175    /// The wallet's newest trade on any market, at or before window_end; null when unknown.
9176    #[serde(default)]
9177    pub last_traded_at: Option<String>,
9178}
9179
9180/// One wallet's net in the window.
9181#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9182#[non_exhaustive]
9183pub struct MarketWalletsInOutNetSellersItem {
9184    /// Lowercase proxy wallet.
9185    pub address: String,
9186    /// The name the site shows: the 0xinsider username, else the shortened address.
9187    pub display_name: String,
9188    /// Today's grade; null for an ungraded or untracked wallet.
9189    #[serde(default)]
9190    pub grade: Option<Grade>,
9191    /// Buys minus sells in the window, both outcomes, in USD: the matched notional, fees excluded.
9192    pub net_usd: f64,
9193    /// Fills in the window.
9194    pub trades: i64,
9195    /// The wallet's newest trade on any market, at or before window_end; null when unknown.
9196    #[serde(default)]
9197    pub last_traded_at: Option<String>,
9198}
9199
9200/// Totals over every wallet that traded the market in the window, not only the listed 50.
9201#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9202#[non_exhaustive]
9203pub struct MarketWalletsInOutSummary {
9204    /// Wallets with a positive net in the window.
9205    pub wallets_in: i64,
9206    /// Wallets with a negative net in the window.
9207    pub wallets_out: i64,
9208    /// The sum of every wallet's net, in USD. A fully rotated wallet nets zero and is on neither side.
9209    pub net_usd: f64,
9210}
9211
9212/// A value this release does not know is kept in `Other`, so a new value never fails a response.
9213#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
9214#[non_exhaustive]
9215pub enum MatchStatus {
9216    /// `scheduled`
9217    #[serde(rename = "scheduled")]
9218    Scheduled,
9219    /// `in_progress`
9220    #[serde(rename = "in_progress")]
9221    InProgress,
9222    /// `halftime`
9223    #[serde(rename = "halftime")]
9224    Halftime,
9225    /// `penalty_shootout`
9226    #[serde(rename = "penalty_shootout")]
9227    PenaltyShootout,
9228    /// `delayed`
9229    #[serde(rename = "delayed")]
9230    Delayed,
9231    /// `suspended`
9232    #[serde(rename = "suspended")]
9233    Suspended,
9234    /// `final`
9235    #[serde(rename = "final")]
9236    Final,
9237    /// `final_overtime`
9238    #[serde(rename = "final_overtime")]
9239    FinalOvertime,
9240    /// `final_shootout`
9241    #[serde(rename = "final_shootout")]
9242    FinalShootout,
9243    /// `awarded`
9244    #[serde(rename = "awarded")]
9245    Awarded,
9246    /// `forfeit`
9247    #[serde(rename = "forfeit")]
9248    Forfeit,
9249    /// `not_necessary`
9250    #[serde(rename = "not_necessary")]
9251    NotNecessary,
9252    /// `postponed`
9253    #[serde(rename = "postponed")]
9254    Postponed,
9255    /// `cancelled`
9256    #[serde(rename = "cancelled")]
9257    Cancelled,
9258    /// `unknown`
9259    #[serde(rename = "unknown")]
9260    Unknown,
9261    /// A value this release does not know, kept as sent.
9262    #[serde(untagged)]
9263    Other(String),
9264}
9265
9266impl MatchStatus {
9267    /// The value as the API spells it.
9268    pub fn as_str(&self) -> &str {
9269        match self {
9270            Self::Scheduled => "scheduled",
9271            Self::InProgress => "in_progress",
9272            Self::Halftime => "halftime",
9273            Self::PenaltyShootout => "penalty_shootout",
9274            Self::Delayed => "delayed",
9275            Self::Suspended => "suspended",
9276            Self::Final => "final",
9277            Self::FinalOvertime => "final_overtime",
9278            Self::FinalShootout => "final_shootout",
9279            Self::Awarded => "awarded",
9280            Self::Forfeit => "forfeit",
9281            Self::NotNecessary => "not_necessary",
9282            Self::Postponed => "postponed",
9283            Self::Cancelled => "cancelled",
9284            Self::Unknown => "unknown",
9285            Self::Other(value) => value,
9286        }
9287    }
9288}
9289
9290impl From<&str> for MatchStatus {
9291    fn from(value: &str) -> Self {
9292        match value {
9293            "scheduled" => Self::Scheduled,
9294            "in_progress" => Self::InProgress,
9295            "halftime" => Self::Halftime,
9296            "penalty_shootout" => Self::PenaltyShootout,
9297            "delayed" => Self::Delayed,
9298            "suspended" => Self::Suspended,
9299            "final" => Self::Final,
9300            "final_overtime" => Self::FinalOvertime,
9301            "final_shootout" => Self::FinalShootout,
9302            "awarded" => Self::Awarded,
9303            "forfeit" => Self::Forfeit,
9304            "not_necessary" => Self::NotNecessary,
9305            "postponed" => Self::Postponed,
9306            "cancelled" => Self::Cancelled,
9307            "unknown" => Self::Unknown,
9308            other => Self::Other(other.to_owned()),
9309        }
9310    }
9311}
9312
9313impl std::fmt::Display for MatchStatus {
9314    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9315        f.write_str(self.as_str())
9316    }
9317}
9318
9319impl AsRef<str> for MatchStatus {
9320    fn as_ref(&self) -> &str {
9321        self.as_str()
9322    }
9323}
9324
9325/// A value this release does not know is kept in `Other`, so a new value never fails a response.
9326#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
9327#[non_exhaustive]
9328pub enum MatchType {
9329    /// `COMPLEMENTARY`
9330    #[serde(rename = "COMPLEMENTARY")]
9331    Complementary,
9332    /// `MINT`
9333    #[serde(rename = "MINT")]
9334    Mint,
9335    /// `MERGE`
9336    #[serde(rename = "MERGE")]
9337    Merge,
9338    /// A value this release does not know, kept as sent.
9339    #[serde(untagged)]
9340    Other(String),
9341}
9342
9343impl MatchType {
9344    /// The value as the API spells it.
9345    pub fn as_str(&self) -> &str {
9346        match self {
9347            Self::Complementary => "COMPLEMENTARY",
9348            Self::Mint => "MINT",
9349            Self::Merge => "MERGE",
9350            Self::Other(value) => value,
9351        }
9352    }
9353}
9354
9355impl From<&str> for MatchType {
9356    fn from(value: &str) -> Self {
9357        match value {
9358            "COMPLEMENTARY" => Self::Complementary,
9359            "MINT" => Self::Mint,
9360            "MERGE" => Self::Merge,
9361            other => Self::Other(other.to_owned()),
9362        }
9363    }
9364}
9365
9366impl std::fmt::Display for MatchType {
9367    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9368        f.write_str(self.as_str())
9369    }
9370}
9371
9372impl AsRef<str> for MatchType {
9373    fn as_ref(&self) -> &str {
9374        self.as_str()
9375    }
9376}
9377
9378#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9379#[non_exhaustive]
9380pub struct McpJsonRpcError {
9381    pub jsonrpc: String,
9382    /// The request's id, or null when the request could not be parsed. Omitted on the answer to an unsolicited response message.
9383    #[serde(default, skip_serializing_if = "Option::is_none")]
9384    pub id: Option<serde_json::Value>,
9385    pub error: McpJsonRpcErrorError,
9386}
9387
9388#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9389#[non_exhaustive]
9390pub struct McpJsonRpcErrorError {
9391    pub code: i64,
9392    pub message: String,
9393    /// Optional JSON-serializable error data.
9394    #[serde(default, skip_serializing_if = "Option::is_none")]
9395    pub data: Option<serde_json::Value>,
9396}
9397
9398/// A value this release does not know is kept in `Other`, so a new value never fails a response.
9399#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
9400#[non_exhaustive]
9401pub enum McpMethod {
9402    /// `initialize`
9403    #[serde(rename = "initialize")]
9404    Initialize,
9405    /// `notifications/initialized`
9406    #[serde(rename = "notifications/initialized")]
9407    NotificationsInitialized,
9408    /// `notifications/cancelled`
9409    #[serde(rename = "notifications/cancelled")]
9410    NotificationsCancelled,
9411    /// `ping`
9412    #[serde(rename = "ping")]
9413    Ping,
9414    /// `tools/list`
9415    #[serde(rename = "tools/list")]
9416    ToolsList,
9417    /// `tools/call`
9418    #[serde(rename = "tools/call")]
9419    ToolsCall,
9420    /// `server/discover`
9421    #[serde(rename = "server/discover")]
9422    ServerDiscover,
9423    /// A value this release does not know, kept as sent.
9424    #[serde(untagged)]
9425    Other(String),
9426}
9427
9428impl McpMethod {
9429    /// The value as the API spells it.
9430    pub fn as_str(&self) -> &str {
9431        match self {
9432            Self::Initialize => "initialize",
9433            Self::NotificationsInitialized => "notifications/initialized",
9434            Self::NotificationsCancelled => "notifications/cancelled",
9435            Self::Ping => "ping",
9436            Self::ToolsList => "tools/list",
9437            Self::ToolsCall => "tools/call",
9438            Self::ServerDiscover => "server/discover",
9439            Self::Other(value) => value,
9440        }
9441    }
9442}
9443
9444impl From<&str> for McpMethod {
9445    fn from(value: &str) -> Self {
9446        match value {
9447            "initialize" => Self::Initialize,
9448            "notifications/initialized" => Self::NotificationsInitialized,
9449            "notifications/cancelled" => Self::NotificationsCancelled,
9450            "ping" => Self::Ping,
9451            "tools/list" => Self::ToolsList,
9452            "tools/call" => Self::ToolsCall,
9453            "server/discover" => Self::ServerDiscover,
9454            other => Self::Other(other.to_owned()),
9455        }
9456    }
9457}
9458
9459impl std::fmt::Display for McpMethod {
9460    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9461        f.write_str(self.as_str())
9462    }
9463}
9464
9465impl AsRef<str> for McpMethod {
9466    fn as_ref(&self) -> &str {
9467        self.as_str()
9468    }
9469}
9470
9471/// A value this release does not know is kept in `Other`, so a new value never fails a response.
9472#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
9473#[non_exhaustive]
9474pub enum Mode {
9475    /// `live`
9476    #[serde(rename = "live")]
9477    Live,
9478    /// `stable`
9479    #[serde(rename = "stable")]
9480    Stable,
9481    /// A value this release does not know, kept as sent.
9482    #[serde(untagged)]
9483    Other(String),
9484}
9485
9486impl Mode {
9487    /// The value as the API spells it.
9488    pub fn as_str(&self) -> &str {
9489        match self {
9490            Self::Live => "live",
9491            Self::Stable => "stable",
9492            Self::Other(value) => value,
9493        }
9494    }
9495}
9496
9497impl From<&str> for Mode {
9498    fn from(value: &str) -> Self {
9499        match value {
9500            "live" => Self::Live,
9501            "stable" => Self::Stable,
9502            other => Self::Other(other.to_owned()),
9503        }
9504    }
9505}
9506
9507impl std::fmt::Display for Mode {
9508    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9509        f.write_str(self.as_str())
9510    }
9511}
9512
9513impl AsRef<str> for Mode {
9514    fn as_ref(&self) -> &str {
9515        self.as_str()
9516    }
9517}
9518
9519/// A value this release does not know is kept in `Other`, so a new value never fails a response.
9520#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
9521#[non_exhaustive]
9522pub enum NextAction {
9523    /// `poll`
9524    #[serde(rename = "poll")]
9525    Poll,
9526    /// `download`
9527    #[serde(rename = "download")]
9528    Download,
9529    /// `resubmit`
9530    #[serde(rename = "resubmit")]
9531    Resubmit,
9532    /// A value this release does not know, kept as sent.
9533    #[serde(untagged)]
9534    Other(String),
9535}
9536
9537impl NextAction {
9538    /// The value as the API spells it.
9539    pub fn as_str(&self) -> &str {
9540        match self {
9541            Self::Poll => "poll",
9542            Self::Download => "download",
9543            Self::Resubmit => "resubmit",
9544            Self::Other(value) => value,
9545        }
9546    }
9547}
9548
9549impl From<&str> for NextAction {
9550    fn from(value: &str) -> Self {
9551        match value {
9552            "poll" => Self::Poll,
9553            "download" => Self::Download,
9554            "resubmit" => Self::Resubmit,
9555            other => Self::Other(other.to_owned()),
9556        }
9557    }
9558}
9559
9560impl std::fmt::Display for NextAction {
9561    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9562        f.write_str(self.as_str())
9563    }
9564}
9565
9566impl AsRef<str> for NextAction {
9567    fn as_ref(&self) -> &str {
9568        self.as_str()
9569    }
9570}
9571
9572/// A value this release does not know is kept in `Other`, so a new value never fails a response.
9573#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
9574#[non_exhaustive]
9575pub enum ObservationSource {
9576    /// `board_snapshot`
9577    #[serde(rename = "board_snapshot")]
9578    BoardSnapshot,
9579    /// `clob_display`
9580    #[serde(rename = "clob_display")]
9581    ClobDisplay,
9582    /// A value this release does not know, kept as sent.
9583    #[serde(untagged)]
9584    Other(String),
9585}
9586
9587impl ObservationSource {
9588    /// The value as the API spells it.
9589    pub fn as_str(&self) -> &str {
9590        match self {
9591            Self::BoardSnapshot => "board_snapshot",
9592            Self::ClobDisplay => "clob_display",
9593            Self::Other(value) => value,
9594        }
9595    }
9596}
9597
9598impl From<&str> for ObservationSource {
9599    fn from(value: &str) -> Self {
9600        match value {
9601            "board_snapshot" => Self::BoardSnapshot,
9602            "clob_display" => Self::ClobDisplay,
9603            other => Self::Other(other.to_owned()),
9604        }
9605    }
9606}
9607
9608impl std::fmt::Display for ObservationSource {
9609    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9610        f.write_str(self.as_str())
9611    }
9612}
9613
9614impl AsRef<str> for ObservationSource {
9615    fn as_ref(&self) -> &str {
9616        self.as_str()
9617    }
9618}
9619
9620/// A value this release does not know is kept in `Other`, so a new value never fails a response.
9621#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
9622#[non_exhaustive]
9623pub enum Outcome {
9624    /// `pending`
9625    #[serde(rename = "pending")]
9626    Pending,
9627    /// `win`
9628    #[serde(rename = "win")]
9629    Win,
9630    /// `loss`
9631    #[serde(rename = "loss")]
9632    Loss,
9633    /// `void`
9634    #[serde(rename = "void")]
9635    Void,
9636    /// A value this release does not know, kept as sent.
9637    #[serde(untagged)]
9638    Other(String),
9639}
9640
9641impl Outcome {
9642    /// The value as the API spells it.
9643    pub fn as_str(&self) -> &str {
9644        match self {
9645            Self::Pending => "pending",
9646            Self::Win => "win",
9647            Self::Loss => "loss",
9648            Self::Void => "void",
9649            Self::Other(value) => value,
9650        }
9651    }
9652}
9653
9654impl From<&str> for Outcome {
9655    fn from(value: &str) -> Self {
9656        match value {
9657            "pending" => Self::Pending,
9658            "win" => Self::Win,
9659            "loss" => Self::Loss,
9660            "void" => Self::Void,
9661            other => Self::Other(other.to_owned()),
9662        }
9663    }
9664}
9665
9666impl std::fmt::Display for Outcome {
9667    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9668        f.write_str(self.as_str())
9669    }
9670}
9671
9672impl AsRef<str> for Outcome {
9673    fn as_ref(&self) -> &str {
9674        self.as_str()
9675    }
9676}
9677
9678/// One outcome token's bucketed candle series.
9679#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9680#[non_exhaustive]
9681pub struct OutcomeCandles {
9682    /// Provider CLOB token id the candles were read for.
9683    pub token_id: String,
9684    /// Canonical side label.
9685    pub outcome: Direction,
9686    /// OHLC candles for this outcome token, ascending by bucket start.
9687    pub candles: Vec<Candle>,
9688}
9689
9690/// A value this release does not know is kept in `Other`, so a new value never fails a response.
9691#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
9692#[non_exhaustive]
9693pub enum PaidDataAccess {
9694    /// `active`
9695    #[serde(rename = "active")]
9696    Active,
9697    /// `lapsed`
9698    #[serde(rename = "lapsed")]
9699    Lapsed,
9700    /// A value this release does not know, kept as sent.
9701    #[serde(untagged)]
9702    Other(String),
9703}
9704
9705impl PaidDataAccess {
9706    /// The value as the API spells it.
9707    pub fn as_str(&self) -> &str {
9708        match self {
9709            Self::Active => "active",
9710            Self::Lapsed => "lapsed",
9711            Self::Other(value) => value,
9712        }
9713    }
9714}
9715
9716impl From<&str> for PaidDataAccess {
9717    fn from(value: &str) -> Self {
9718        match value {
9719            "active" => Self::Active,
9720            "lapsed" => Self::Lapsed,
9721            other => Self::Other(other.to_owned()),
9722        }
9723    }
9724}
9725
9726impl std::fmt::Display for PaidDataAccess {
9727    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9728        f.write_str(self.as_str())
9729    }
9730}
9731
9732impl AsRef<str> for PaidDataAccess {
9733    fn as_ref(&self) -> &str {
9734        self.as_str()
9735    }
9736}
9737
9738#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9739#[non_exhaustive]
9740pub struct PickHolder {
9741    pub address: String,
9742    #[serde(default)]
9743    pub name: Option<String>,
9744    /// All-time trader grade (S, A, B, C, D, F).
9745    #[serde(default)]
9746    pub grade: Option<String>,
9747    /// 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.
9748    #[serde(default)]
9749    pub last_traded_at: Option<String>,
9750    /// 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.
9751    #[serde(default, skip_serializing_if = "Option::is_none")]
9752    pub profile_segment: Option<String>,
9753    pub shares: f64,
9754    /// 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.
9755    #[serde(default, skip_serializing_if = "Option::is_none")]
9756    pub entry_value_usd: Option<f64>,
9757    /// 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.
9758    #[serde(default, skip_serializing_if = "Option::is_none")]
9759    pub category_win_rate: Option<f64>,
9760    /// 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.
9761    #[serde(default, skip_serializing_if = "Option::is_none")]
9762    pub category_win_record: Option<PickHolderCategoryWinRecord>,
9763    /// 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.
9764    #[serde(default, skip_serializing_if = "Option::is_none")]
9765    pub category_avg_price: Option<f64>,
9766    /// 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.
9767    #[serde(default, skip_serializing_if = "Option::is_none")]
9768    pub category_win_rate_game: Option<String>,
9769    /// 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.
9770    #[serde(default, skip_serializing_if = "Option::is_none")]
9771    pub category_win_rate_status: Option<CategoryWinRateStatus>,
9772    /// 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.
9773    #[serde(default, skip_serializing_if = "Option::is_none")]
9774    pub wallet_age_days: Option<f64>,
9775    /// 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.
9776    #[serde(default, skip_serializing_if = "Option::is_none")]
9777    pub is_new_wallet: Option<bool>,
9778    /// 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.
9779    #[serde(default, skip_serializing_if = "Option::is_none")]
9780    pub markets_traded: Option<i64>,
9781    /// 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.
9782    #[serde(default, skip_serializing_if = "Option::is_none")]
9783    pub is_bot: Option<bool>,
9784    /// 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.
9785    #[serde(default, skip_serializing_if = "Option::is_none")]
9786    pub x_username: Option<String>,
9787}
9788
9789/// 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.
9790#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9791#[non_exhaustive]
9792pub struct PickHolderCategoryWinRecord {
9793    /// Settled markets in the category that this wallet closed with a profit.
9794    pub wins: i64,
9795    /// 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.
9796    pub decided: i64,
9797}
9798
9799/// 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.
9800#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9801#[non_exhaustive]
9802pub struct PickLeadBacker {
9803    /// Lead trader wallet address.
9804    pub address: String,
9805    /// Recorded provider display name.
9806    #[serde(default)]
9807    pub name: Option<String>,
9808    /// Trader grade recorded at publication.
9809    pub grade: String,
9810    /// Canonical sport of the recorded directional history.
9811    pub category: String,
9812    /// 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.
9813    pub position_usd: f64,
9814    /// 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.
9815    #[serde(default, skip_serializing_if = "Option::is_none")]
9816    pub net_position_usd: Option<f64>,
9817    /// Start time of the provider position fetch used at publication. This conservative observation clock precedes completion; the position is not a live balance.
9818    pub position_observed_at: String,
9819    /// Distinct directional events in the recorded category history.
9820    pub directional_event_count: i64,
9821    /// 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.
9822    pub profitable_event_count: i64,
9823    /// Realized P&L over the recorded directional category sample, in USD. Excludes open positions and later changes.
9824    pub realized_pnl_usd: f64,
9825    /// Recorded entry basis of that directional sample, in USD; not a claim of complete trading costs or fees.
9826    pub entry_basis_usd: f64,
9827    /// 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.
9828    pub roi: f64,
9829    /// Peak-to-trough realized P&L drawdown after each event result in the recorded sample, in USD. Excludes intragame, unrealized, and account equity drawdown.
9830    pub max_realized_drawdown_usd: f64,
9831    /// Timestamp when the directional history evidence was recorded, separate from the provider position snapshot clock.
9832    pub recorded_at: String,
9833}
9834
9835#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9836#[non_exhaustive]
9837pub struct PickOfTheDay {
9838    /// Full success containing entitled proof-readable picks.
9839    pub state: String,
9840    /// The pick's local publication date (YYYY-MM-DD).
9841    #[serde(default, skip_serializing_if = "Option::is_none")]
9842    pub pick_date: Option<String>,
9843    /// Deprecated compatibility daily release slot; use pick_id for identity and publication_order for scheduling.
9844    #[serde(default, skip_serializing_if = "Option::is_none")]
9845    pub pick_rank: Option<i64>,
9846    /// Published picks for this product day in the returned display order. Use pick_id for identity.
9847    #[serde(default, skip_serializing_if = "Option::is_none")]
9848    pub picks: Option<Vec<PickOfTheDay>>,
9849    /// Number of items in `picks`: the proof-readable picks. Picks held in `proof_pending_picks` are not counted.
9850    #[serde(default, skip_serializing_if = "Option::is_none")]
9851    pub pick_count: Option<i64>,
9852    /// 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.
9853    #[serde(default, skip_serializing_if = "Option::is_none")]
9854    pub scheduled_picks: Option<Vec<ScheduledPickSlot>>,
9855    /// Human-readable matchup (e.g. "Portugal vs. Uzbekistan").
9856    #[serde(default, skip_serializing_if = "Option::is_none")]
9857    pub matchup: Option<String>,
9858    /// Recorded canonical sport category. Prefer display_category for the public competition label.
9859    #[serde(default, skip_serializing_if = "Option::is_none")]
9860    pub category: Option<String>,
9861    /// 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.
9862    #[serde(default, skip_serializing_if = "Option::is_none")]
9863    pub display_category: Option<String>,
9864    /// Provider platform. Always polymarket.
9865    #[serde(default, skip_serializing_if = "Option::is_none")]
9866    pub platform: Option<String>,
9867    /// The pick's stored release instant. Use the returned timestamp; published_at records when publication occurred.
9868    #[serde(default, skip_serializing_if = "Option::is_none")]
9869    pub release_at: Option<String>,
9870    /// 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`.
9871    #[serde(default, skip_serializing_if = "Option::is_none")]
9872    pub is_locked: Option<bool>,
9873    /// 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).
9874    #[serde(default, skip_serializing_if = "Option::is_none")]
9875    pub game_started: Option<bool>,
9876    /// 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.
9877    #[serde(default, skip_serializing_if = "Option::is_none")]
9878    pub game_ended: Option<bool>,
9879    /// Settlement outcome of the backed side; 'pending' until the market resolves.
9880    #[serde(default, skip_serializing_if = "Option::is_none")]
9881    pub outcome: Option<Outcome>,
9882    /// 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.
9883    #[serde(default, skip_serializing_if = "Option::is_none")]
9884    pub outcome_display: Option<String>,
9885    /// 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").
9886    #[serde(default, skip_serializing_if = "Option::is_none")]
9887    pub pick_outcome_label: Option<String>,
9888    /// The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the backed outcome; omitted when unavailable (e.g. unsynced markets).
9889    #[serde(default, skip_serializing_if = "Option::is_none")]
9890    pub token_id: Option<String>,
9891    /// The backed side phrased as a bet (e.g. "Portugal to win").
9892    #[serde(default, skip_serializing_if = "Option::is_none")]
9893    pub position: Option<String>,
9894    /// 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.
9895    #[serde(default, skip_serializing_if = "Option::is_none")]
9896    pub side_summary: Option<String>,
9897    /// S/A wallet count on the backed side in the public V1 compatibility projection.
9898    #[serde(default, skip_serializing_if = "Option::is_none")]
9899    pub sharp_wallet_count: Option<i64>,
9900    /// Deprecated spelling of sharp_wallet_count with the same value.
9901    #[serde(default, skip_serializing_if = "Option::is_none")]
9902    pub smart_wallet_count: Option<i64>,
9903    /// Best recorded S/A grade in the public V1 compatibility projection.
9904    #[serde(default, skip_serializing_if = "Option::is_none")]
9905    pub top_grade: Option<String>,
9906    /// Recorded sharp-money magnitude in USD when available.
9907    #[serde(default, skip_serializing_if = "Option::is_none")]
9908    pub sharp_usd: Option<f64>,
9909    /// Deprecated spelling of sharp_usd with the same value.
9910    #[serde(default, skip_serializing_if = "Option::is_none")]
9911    pub smart_usd: Option<f64>,
9912    /// 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.
9913    #[serde(default, skip_serializing_if = "Option::is_none")]
9914    pub backed_price: Option<f64>,
9915    /// 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.
9916    #[serde(default, skip_serializing_if = "Option::is_none")]
9917    pub entry_price_note: Option<String>,
9918    /// 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.
9919    #[serde(default, skip_serializing_if = "Option::is_none")]
9920    pub odds_display: Option<String>,
9921    /// 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.
9922    #[serde(default, skip_serializing_if = "Option::is_none")]
9923    pub stake_usd: Option<f64>,
9924    /// 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.
9925    #[serde(default, skip_serializing_if = "Option::is_none")]
9926    pub return_usd: Option<f64>,
9927    /// 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.
9928    #[serde(default, skip_serializing_if = "Option::is_none")]
9929    pub return_per_100: Option<f64>,
9930    /// 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.
9931    #[serde(default, skip_serializing_if = "Option::is_none")]
9932    pub payout_display: Option<String>,
9933    /// 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.
9934    #[serde(default, skip_serializing_if = "Option::is_none")]
9935    pub profit_display: Option<String>,
9936    /// 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.
9937    #[serde(default, skip_serializing_if = "Option::is_none")]
9938    pub clv_status: Option<String>,
9939    /// 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.
9940    #[serde(default, skip_serializing_if = "Option::is_none")]
9941    pub clv_basis: Option<String>,
9942    /// 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.
9943    #[serde(default, skip_serializing_if = "Option::is_none")]
9944    pub clv_pct: Option<f64>,
9945    /// Backend-formatted signed CLV percentage, present exactly when clv_pct is present.
9946    #[serde(default, skip_serializing_if = "Option::is_none")]
9947    pub clv_display: Option<String>,
9948    /// Backend-owned CLV formula text with the entry probability, close probability, and rounded result. Provider timestamps remain private.
9949    #[serde(default, skip_serializing_if = "Option::is_none")]
9950    pub clv_explanation: Option<String>,
9951    /// 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.
9952    #[serde(default, skip_serializing_if = "Option::is_none")]
9953    pub unit_score: Option<f64>,
9954    /// Backend-formatted signed unit score, present exactly when unit_score is present.
9955    #[serde(default, skip_serializing_if = "Option::is_none")]
9956    pub unit_score_display: Option<String>,
9957    /// Recorded sharp-money share as a 0..1 fraction when available. This is not a winning probability.
9958    #[serde(default, skip_serializing_if = "Option::is_none")]
9959    pub sharp_pct: Option<f64>,
9960    /// Recorded market-implied probability as a 0..1 fraction when available.
9961    #[serde(default, skip_serializing_if = "Option::is_none")]
9962    pub market_pct: Option<f64>,
9963    /// 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.
9964    #[serde(default, skip_serializing_if = "Option::is_none")]
9965    pub qualifying_expert: Option<PickOfTheDayQualifyingExpert>,
9966    /// Public V1 S/A wallet count on the backed side, equal to sharp_wallet_count.
9967    #[serde(default, skip_serializing_if = "Option::is_none")]
9968    pub traders: Option<i64>,
9969    /// 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.
9970    #[serde(default, skip_serializing_if = "Option::is_none")]
9971    pub backed_sharp_usd: Option<f64>,
9972    /// Bounded S/A holder display projection from the recorded snapshot. Historical rows retain their recorded display shape.
9973    #[serde(default, skip_serializing_if = "Option::is_none")]
9974    pub holders: Option<Vec<PickHolder>>,
9975    /// 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.
9976    #[serde(default, skip_serializing_if = "Option::is_none")]
9977    pub display_holders: Option<Vec<PickHolder>>,
9978    /// S/A holder count for the public V1 compatibility projection. display_holders can include additional grades.
9979    #[serde(default, skip_serializing_if = "Option::is_none")]
9980    pub holder_count: Option<i64>,
9981    /// Display-ready explanation of the recorded pick. Render the returned text rather than reconstructing it from holder counts or grades.
9982    #[serde(default, skip_serializing_if = "Option::is_none")]
9983    pub thesis: Option<String>,
9984    /// Canonical web market URL.
9985    #[serde(default, skip_serializing_if = "Option::is_none")]
9986    pub market_url: Option<String>,
9987    /// 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.
9988    #[serde(default, skip_serializing_if = "Option::is_none")]
9989    pub polymarket_url: Option<String>,
9990    /// The canonical /event game-page slug (one neutral page per game); omitted when the game has no neutral event page.
9991    #[serde(default, skip_serializing_if = "Option::is_none")]
9992    pub event_slug: Option<String>,
9993    /// Backend-resolved /event destination slug for the source market. Omitted outside full responses; null is an authoritative no-link decision.
9994    #[serde(default, skip_serializing_if = "Option::is_none")]
9995    pub event_link_slug: Option<String>,
9996    /// 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.
9997    #[serde(default, skip_serializing_if = "Option::is_none")]
9998    pub sports_context: Option<PickSportsContext>,
9999    /// Risk disclaimer shown with every pick.
10000    #[serde(default, skip_serializing_if = "Option::is_none")]
10001    pub disclaimer: Option<String>,
10002    /// 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.
10003    #[serde(default, skip_serializing_if = "Option::is_none")]
10004    pub proof_pending_picks: Option<Vec<ProofPendingPickSlot>>,
10005    /// Optional full-response entry authorization. Missing or expired authorization cannot authorize an automated entry.
10006    #[serde(default, skip_serializing_if = "Option::is_none")]
10007    pub entry_authorization: Option<PotdEntryAuthorization>,
10008    /// Unauthorized unresolved published or scheduled ranks. Contains no game, provider identity, price, or identifying clock. Pro may upgrade to Max to open these ranks.
10009    #[serde(default, skip_serializing_if = "Option::is_none")]
10010    pub locked_picks: Option<Vec<PickOfTheDayLockedPicksItem>>,
10011    /// Actionable status, including Upgrade to Max when only locked ranks are published.
10012    #[serde(default, skip_serializing_if = "Option::is_none")]
10013    pub message: Option<String>,
10014    /// Stable pick row identity as decimal text. Never use a quality rank as identity.
10015    #[serde(default, skip_serializing_if = "Option::is_none")]
10016    pub pick_id: Option<String>,
10017    /// Compatibility release slot. No quality claim; historic scheduling order is retained.
10018    #[serde(default, skip_serializing_if = "Option::is_none")]
10019    pub publication_order: Option<i64>,
10020    /// Viewer-independent free selection designation. New rows store it explicitly; historic null storage uses the original free slot.
10021    #[serde(default, skip_serializing_if = "Option::is_none")]
10022    pub is_free_selection: Option<bool>,
10023    /// 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.
10024    #[serde(default)]
10025    pub supersedes_pick_id: Option<String>,
10026    /// Optional full-only lead wallet publication facts. Omitted on legacy picks or when the recorded evidence is unavailable.
10027    #[serde(default, skip_serializing_if = "Option::is_none")]
10028    pub lead_backer: Option<PickLeadBacker>,
10029}
10030
10031#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10032#[non_exhaustive]
10033pub struct PickOfTheDayArchive {
10034    /// 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.
10035    pub picks: Vec<PickOfTheDayArchiveEntry>,
10036    /// 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.
10037    pub days: Vec<PickOfTheDayArchiveDay>,
10038    pub hit_rate: PickOfTheDayHitRate,
10039}
10040
10041#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10042#[non_exhaustive]
10043pub struct PickOfTheDayArchiveDay {
10044    /// The product day (YYYY-MM-DD).
10045    pub date: String,
10046    /// Published picks on the day: wins + losses + void + pending.
10047    pub picks: i64,
10048    /// 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.
10049    pub wins: i64,
10050    /// Picks on the day that resolved as a loss, counted by the same pass as hit_rate.losses.
10051    pub losses: i64,
10052    /// 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.
10053    pub void: i64,
10054    /// 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.
10055    pub pending: i64,
10056    /// 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.
10057    #[serde(default, skip_serializing_if = "Option::is_none")]
10058    pub unit_score: Option<f64>,
10059    /// 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.
10060    #[serde(default, skip_serializing_if = "Option::is_none")]
10061    pub unit_score_display: Option<String>,
10062    /// 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.
10063    #[serde(default, skip_serializing_if = "Option::is_none")]
10064    pub sweep: Option<Sweep>,
10065}
10066
10067#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10068#[non_exhaustive]
10069pub struct PickOfTheDayArchiveEntry {
10070    /// The pick's local publication date (YYYY-MM-DD).
10071    pub pick_date: String,
10072    /// Deprecated compatibility daily release slot; use pick_id for identity and publication_order for scheduling.
10073    pub pick_rank: i64,
10074    /// 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.
10075    #[serde(default, skip_serializing_if = "Option::is_none")]
10076    pub published_at: Option<String>,
10077    /// Human-readable matchup (e.g. "Portugal vs. Uzbekistan").
10078    #[serde(default, skip_serializing_if = "Option::is_none")]
10079    pub matchup: Option<String>,
10080    /// Frozen canonical sport bucket (e.g. "Basketball", "MMA", or "Soccer"). Existing semantics are unchanged; presentation consumers should prefer display_category when present.
10081    #[serde(default, skip_serializing_if = "Option::is_none")]
10082    pub category: Option<String>,
10083    /// 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.
10084    #[serde(default, skip_serializing_if = "Option::is_none")]
10085    pub display_category: Option<String>,
10086    /// 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.
10087    #[serde(default, skip_serializing_if = "Option::is_none")]
10088    pub image_url: Option<String>,
10089    /// The backed side's outcome label. Omitted for a still-pending pick when the request is not from an authenticated Pro key.
10090    #[serde(default, skip_serializing_if = "Option::is_none")]
10091    pub pick_outcome_label: Option<String>,
10092    /// Recorded top grade on the backed side in the public V1 compatibility projection. Omitted when unavailable. Historical values remain recorded snapshots.
10093    #[serde(default, skip_serializing_if = "Option::is_none")]
10094    pub top_grade: Option<String>,
10095    /// Settlement outcome of the backed side; 'pending' until the market resolves.
10096    pub outcome: Outcome,
10097    /// 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.
10098    #[serde(default, skip_serializing_if = "Option::is_none")]
10099    pub outcome_display: Option<String>,
10100    /// 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.
10101    #[serde(default, skip_serializing_if = "Option::is_none")]
10102    pub resolved_at: Option<String>,
10103    /// 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.
10104    #[serde(default, skip_serializing_if = "Option::is_none")]
10105    pub stake_usd: Option<f64>,
10106    /// 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.
10107    #[serde(default, skip_serializing_if = "Option::is_none")]
10108    pub return_usd: Option<f64>,
10109    /// 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.
10110    #[serde(default, skip_serializing_if = "Option::is_none")]
10111    pub return_per_100: Option<f64>,
10112    /// 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.
10113    #[serde(default, skip_serializing_if = "Option::is_none")]
10114    pub payout_display: Option<String>,
10115    /// 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.
10116    #[serde(default, skip_serializing_if = "Option::is_none")]
10117    pub backed_price: Option<f64>,
10118    /// Closing-line value toward the backed side, computed as (close / entry - 1) * 100. Omitted when the row is gated, ineligible, or not measured.
10119    #[serde(default, skip_serializing_if = "Option::is_none")]
10120    pub clv_pct: Option<f64>,
10121    /// Backend-formatted signed CLV percentage, present exactly when clv_pct is present.
10122    #[serde(default, skip_serializing_if = "Option::is_none")]
10123    pub clv_display: Option<String>,
10124    /// 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.
10125    #[serde(default, skip_serializing_if = "Option::is_none")]
10126    pub clv_entry_price: Option<f64>,
10127    /// 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.
10128    #[serde(default, skip_serializing_if = "Option::is_none")]
10129    pub clv_close_price: Option<f64>,
10130    /// Whether CLV applies. A visible resolved pick published after kickoff is not_applicable.
10131    #[serde(default, skip_serializing_if = "Option::is_none")]
10132    pub clv_applicability: Option<ClvApplicability>,
10133    /// 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.
10134    #[serde(default, skip_serializing_if = "Option::is_none")]
10135    pub clv_explanation: Option<String>,
10136    /// 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.
10137    #[serde(default, skip_serializing_if = "Option::is_none")]
10138    pub clv_status: Option<String>,
10139    /// 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.
10140    #[serde(default, skip_serializing_if = "Option::is_none")]
10141    pub clv_basis: Option<String>,
10142    /// 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.
10143    #[serde(default, skip_serializing_if = "Option::is_none")]
10144    pub unit_score: Option<f64>,
10145    /// Backend-formatted signed unit score, present exactly when unit_score is present.
10146    #[serde(default, skip_serializing_if = "Option::is_none")]
10147    pub unit_score_display: Option<String>,
10148    /// The account or paid tier needed to open this unresolved rank.
10149    #[serde(default, skip_serializing_if = "Option::is_none")]
10150    pub required_tier: Option<RequiredTier>,
10151    /// True for an unauthorized unresolved row. Game identity, category, image, publication clock and all backed facts are omitted.
10152    #[serde(default, skip_serializing_if = "Option::is_none")]
10153    pub backed_side_locked: Option<bool>,
10154    /// Stable pick row identity as decimal text. Never use a quality rank as identity.
10155    pub pick_id: String,
10156    /// Compatibility release slot. No quality claim; historic scheduling order is retained.
10157    pub publication_order: i64,
10158    /// Viewer-independent free selection designation. New rows store it explicitly; historic null storage uses the original free slot.
10159    pub is_free_selection: bool,
10160    /// 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.
10161    #[serde(default)]
10162    pub supersedes_pick_id: Option<String>,
10163}
10164
10165/// Select using the entry commitment_version, never implicit payload shape. All historic v1 hashes remain unchanged.
10166pub type PickOfTheDayCommitmentPayload = serde_json::Value;
10167
10168/// 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.
10169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10170#[non_exhaustive]
10171pub struct PickOfTheDayCommitmentPayloadV1 {
10172    /// 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".
10173    pub backed_price: String,
10174    /// Provider condition id of the backed market.
10175    pub condition_id: String,
10176    /// Frozen provider kickoff, whole seconds, UTC, literal Z. Fixed precision, never a shortest-lossless rendering.
10177    pub kickoff: String,
10178    /// ET product day (YYYY-MM-DD).
10179    pub pick_date: String,
10180    /// Index of the backed outcome within the market.
10181    pub pick_outcome_index: i64,
10182    /// Frozen display label of the backed outcome.
10183    pub pick_outcome_label: String,
10184    /// 1-based daily slot.
10185    pub pick_rank: i64,
10186    /// Provider platform. Always polymarket.
10187    pub platform: String,
10188}
10189
10190/// 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.
10191#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10192#[non_exhaustive]
10193pub struct PickOfTheDayCommitmentPayloadV2 {
10194    /// 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".
10195    pub backed_price: String,
10196    /// Provider condition id of the backed market.
10197    pub condition_id: String,
10198    /// Frozen provider kickoff, whole seconds, UTC, literal Z. Fixed precision, never a shortest-lossless rendering.
10199    pub kickoff: String,
10200    /// ET product day (YYYY-MM-DD).
10201    pub pick_date: String,
10202    /// Index of the backed outcome within the market.
10203    pub pick_outcome_index: i64,
10204    /// Frozen display label of the backed outcome.
10205    pub pick_outcome_label: String,
10206    /// Provider platform. Always polymarket.
10207    pub platform: String,
10208    /// Stable pick row identity as decimal text. Never use a quality rank as identity.
10209    pub pick_id: String,
10210    pub version: i64,
10211}
10212
10213#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10214#[non_exhaustive]
10215pub struct PickOfTheDayHitRate {
10216    /// Number of decided picks that won.
10217    pub wins: i64,
10218    /// Number of decided picks that lost.
10219    pub losses: i64,
10220    /// Number of decided picks (wins + losses); excludes void and pending.
10221    pub decided: i64,
10222    /// Rolling hit rate as a percentage (wins / decided * 100, to 1 decimal); 0 when none are decided.
10223    pub pct: f64,
10224    /// Number of picks that resolved void (excluded from the hit rate).
10225    pub void: i64,
10226    /// Number of picks still pending resolution (excluded from the hit rate).
10227    pub pending: i64,
10228    /// The flat stake every money figure here assumes, in USD: 1000 since 2026-09-22 (100 before). Always present.
10229    pub stake_usd: f64,
10230    /// 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.
10231    pub net_profit_usd: f64,
10232    /// 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.
10233    pub staked_usd: f64,
10234    /// Return on the staked amount as a percentage (net_profit_usd / staked_usd * 100, to 1 decimal); 0 when nothing is staked.
10235    pub roi_pct: f64,
10236    /// 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.
10237    pub net_profit_display: String,
10238    /// 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.
10239    pub roi_display: String,
10240    /// Pre-formatted win rate for display, e.g. "92.3%". One decimal, unsigned. Convenience only; pct is the source value.
10241    pub win_rate_display: String,
10242    /// Cumulative net return in stake units over the same valued win/loss population as net_profit_usd.
10243    #[serde(default, skip_serializing_if = "Option::is_none")]
10244    pub unit_score: Option<f64>,
10245    /// Backend-formatted signed cumulative unit score, for example "+1.25u". Omitted when no valued settled pick contributes to the aggregate.
10246    #[serde(default, skip_serializing_if = "Option::is_none")]
10247    pub unit_score_display: Option<String>,
10248    /// Visible resolved archive rows with no CLV capture disposition yet.
10249    pub clv_pending: i64,
10250    /// Visible resolved archive rows with a terminal non-measured CLV disposition.
10251    pub clv_unavailable: i64,
10252    /// Aggregate CLV state. Counts remain available for mixed measured/pending/unavailable populations.
10253    pub clv_state: ClvState,
10254    /// 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.
10255    pub clv_eligible: i64,
10256    /// Every visible resolved archive row, including post-kickoff picks. A price-gated current row is excluded until its backed side becomes visible.
10257    pub clv_total: i64,
10258    /// Eligible resolved public rows with a measured Polymarket CLOB close.
10259    pub clv_measured: i64,
10260    /// Visible resolved rows published before kickoff. This is the CLV coverage denominator.
10261    pub clv_applicable: i64,
10262    /// Visible resolved rows published after kickoff. These rows remain public but do not enter coverage.
10263    pub clv_not_applicable: i64,
10264    /// Measured divided by clv_applicable as a percentage. Omitted when clv_applicable is zero.
10265    #[serde(default, skip_serializing_if = "Option::is_none")]
10266    pub clv_coverage_pct: Option<f64>,
10267    /// Backend-formatted measured/clv_applicable coverage percentage.
10268    #[serde(default, skip_serializing_if = "Option::is_none")]
10269    pub clv_coverage_display: Option<String>,
10270    /// Backend-owned coverage count text, including the excluded post-kickoff count.
10271    #[serde(default, skip_serializing_if = "Option::is_none")]
10272    pub clv_coverage_explanation: Option<String>,
10273    /// 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.
10274    #[serde(default, skip_serializing_if = "Option::is_none")]
10275    pub clv_avg_pct: Option<f64>,
10276    /// Backend-formatted signed average CLV percentage, present when clv_avg_pct is present.
10277    #[serde(default, skip_serializing_if = "Option::is_none")]
10278    pub clv_avg_display: Option<String>,
10279    /// 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.
10280    #[serde(default, skip_serializing_if = "Option::is_none")]
10281    pub clv_avg_pp: Option<f64>,
10282    /// 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.
10283    #[serde(default, skip_serializing_if = "Option::is_none")]
10284    pub clv_avg_pp_display: Option<String>,
10285    /// Measured public rows where close is strictly greater than entry.
10286    pub clv_beats_close: i64,
10287    /// Measured public rows where close exactly equals entry.
10288    pub clv_ties: i64,
10289    /// 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.
10290    pub series: Vec<PickOfTheDayHitRateSeriesItem>,
10291}
10292
10293#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10294#[non_exhaustive]
10295pub struct PickOfTheDayHitRateSeriesItem {
10296    /// The decided pick's publish date (YYYY-MM-DD).
10297    pub date: String,
10298    /// 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.
10299    pub net_profit_usd: f64,
10300    /// Running rolling hit rate (wins / decided * 100, to 1 decimal) through this pick.
10301    pub hit_rate_pct: f64,
10302}
10303
10304/// 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.
10305#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10306#[non_exhaustive]
10307pub struct PickOfTheDayLedger {
10308    /// One entry per published (pick_date, pick_rank), ascending by pick_date then pick_rank.
10309    pub entries: Vec<PickOfTheDayLedgerEntry>,
10310    /// Number of entries, all states included.
10311    pub entry_count: i64,
10312    /// Entries committed to and not yet settled.
10313    pub sealed_count: i64,
10314    /// Entries committed to and verifiable now.
10315    pub opened_count: i64,
10316    /// 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.
10317    pub uncommitted_count: i64,
10318}
10319
10320/// One ledger entry. Read `state` to know which shape you have; the three are disjoint.
10321///
10322/// Discriminated by `state`. A `state` this release does not know is kept whole in
10323/// `Unknown`, so a new kind never fails a response.
10324#[derive(Debug, Clone, PartialEq)]
10325#[non_exhaustive]
10326pub enum PickOfTheDayLedgerEntry {
10327    /// `state` is `sealed`.
10328    Sealed(PickOfTheDayLedgerSealedEntry),
10329    /// `state` is `opened`.
10330    Opened(PickOfTheDayLedgerOpenedEntry),
10331    /// `state` is `uncommitted`.
10332    Uncommitted(PickOfTheDayLedgerUncommittedEntry),
10333    /// A `state` this release does not know, kept as sent.
10334    Unknown(serde_json::Value),
10335}
10336
10337impl<'de> Deserialize<'de> for PickOfTheDayLedgerEntry {
10338    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
10339        let value = serde_json::Value::deserialize(deserializer)?;
10340        match value.get("state").and_then(serde_json::Value::as_str) {
10341            Some("sealed") => serde_json::from_value(value)
10342                .map(Self::Sealed)
10343                .map_err(de::Error::custom),
10344            Some("opened") => serde_json::from_value(value)
10345                .map(Self::Opened)
10346                .map_err(de::Error::custom),
10347            Some("uncommitted") => serde_json::from_value(value)
10348                .map(Self::Uncommitted)
10349                .map_err(de::Error::custom),
10350            _ => Ok(Self::Unknown(value)),
10351        }
10352    }
10353}
10354
10355impl Serialize for PickOfTheDayLedgerEntry {
10356    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
10357        match self {
10358            Self::Sealed(inner) => inner.serialize(serializer),
10359            Self::Opened(inner) => inner.serialize(serializer),
10360            Self::Uncommitted(inner) => inner.serialize(serializer),
10361            Self::Unknown(inner) => inner.serialize(serializer),
10362        }
10363    }
10364}
10365
10366/// 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.
10367#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10368#[non_exhaustive]
10369pub struct PickOfTheDayLedgerOpenedEntry {
10370    pub state: String,
10371    /// ET product day the pick belongs to (YYYY-MM-DD).
10372    pub pick_date: String,
10373    /// Deprecated compatibility daily release slot; use pick_id for identity and publication_order for scheduling.
10374    pub pick_rank: i64,
10375    /// sha256(canonical_json(payload) || nonce), lowercase hex, no 0x prefix. Publishable the moment the pick releases: without the nonce it is not invertible.
10376    pub commitment_hash: String,
10377    /// 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.
10378    pub commitment_nonce: String,
10379    /// The construction the hash was taken with, stated in the response so a verifier never has to guess the serialization.
10380    pub commitment_algo: String,
10381    /// 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.
10382    pub sealed_at: String,
10383    /// 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.
10384    #[serde(default)]
10385    pub resolved_at: Option<String>,
10386    /// 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.
10387    pub kickoff: String,
10388    pub payload: PickOfTheDayCommitmentPayload,
10389    /// How the pick settled. Never pending: a pending pick is a sealed entry.
10390    pub outcome: PickOfTheDayLedgerOpenedEntryOutcome,
10391    /// 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.
10392    #[serde(default)]
10393    pub withdrawal_reason: Option<WithdrawalReason>,
10394    /// Frozen matchup, for a reader.
10395    pub matchup: String,
10396    /// Frozen canonical sport bucket (for example Basketball or MMA), not the exact public league identity; the archive owns that.
10397    pub category: String,
10398    /// The pick's stable public page, `https://0xinsider.com/pick-of-the-day/picks/{pick_id}`.
10399    pub permalink: String,
10400    /// Stable pick row identity as decimal text. Never use a quality rank as identity.
10401    pub pick_id: String,
10402    /// Compatibility release slot. No quality claim; historic scheduling order is retained.
10403    pub publication_order: i64,
10404    /// Viewer-independent free selection designation. New rows store it explicitly; historic null storage uses the original free slot.
10405    pub is_free_selection: bool,
10406    /// 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.
10407    #[serde(default)]
10408    pub supersedes_pick_id: Option<String>,
10409    /// Explicit proof provenance: 1 retains historic eight-field canonical JSON; 2 binds stable pick_id and version without pick_rank.
10410    pub commitment_version: i64,
10411}
10412
10413/// A value this release does not know is kept in `Other`, so a new value never fails a response.
10414#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
10415#[non_exhaustive]
10416pub enum PickOfTheDayLedgerOpenedEntryOutcome {
10417    /// `win`
10418    #[serde(rename = "win")]
10419    Win,
10420    /// `loss`
10421    #[serde(rename = "loss")]
10422    Loss,
10423    /// `void`
10424    #[serde(rename = "void")]
10425    Void,
10426    /// A value this release does not know, kept as sent.
10427    #[serde(untagged)]
10428    Other(String),
10429}
10430
10431impl PickOfTheDayLedgerOpenedEntryOutcome {
10432    /// The value as the API spells it.
10433    pub fn as_str(&self) -> &str {
10434        match self {
10435            Self::Win => "win",
10436            Self::Loss => "loss",
10437            Self::Void => "void",
10438            Self::Other(value) => value,
10439        }
10440    }
10441}
10442
10443impl From<&str> for PickOfTheDayLedgerOpenedEntryOutcome {
10444    fn from(value: &str) -> Self {
10445        match value {
10446            "win" => Self::Win,
10447            "loss" => Self::Loss,
10448            "void" => Self::Void,
10449            other => Self::Other(other.to_owned()),
10450        }
10451    }
10452}
10453
10454impl std::fmt::Display for PickOfTheDayLedgerOpenedEntryOutcome {
10455    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
10456        f.write_str(self.as_str())
10457    }
10458}
10459
10460impl AsRef<str> for PickOfTheDayLedgerOpenedEntryOutcome {
10461    fn as_ref(&self) -> &str {
10462        self.as_str()
10463    }
10464}
10465
10466/// 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.
10467#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10468#[non_exhaustive]
10469pub struct PickOfTheDayLedgerSealedEntry {
10470    pub state: String,
10471    /// ET product day the pick belongs to (YYYY-MM-DD).
10472    pub pick_date: String,
10473    /// Deprecated compatibility daily release slot; use pick_id for identity and publication_order for scheduling.
10474    pub pick_rank: i64,
10475    /// sha256(canonical_json(payload) || nonce), lowercase hex, no 0x prefix. Publishable the moment the pick releases: without the nonce it is not invertible.
10476    pub commitment_hash: String,
10477    /// The construction the hash was taken with, stated in the response so a verifier never has to guess the serialization.
10478    pub commitment_algo: String,
10479    /// 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.
10480    pub sealed_at: String,
10481    /// The pick's stable public page, `https://0xinsider.com/pick-of-the-day/picks/{pick_id}`.
10482    pub permalink: String,
10483    /// Stable pick row identity as decimal text. Never use a quality rank as identity.
10484    pub pick_id: String,
10485    /// Compatibility release slot. No quality claim; historic scheduling order is retained.
10486    pub publication_order: i64,
10487    /// Viewer-independent free selection designation. New rows store it explicitly; historic null storage uses the original free slot.
10488    pub is_free_selection: bool,
10489    /// 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.
10490    #[serde(default)]
10491    pub supersedes_pick_id: Option<String>,
10492    /// Explicit proof provenance: 1 retains historic eight-field canonical JSON; 2 binds stable pick_id and version without pick_rank.
10493    pub commitment_version: i64,
10494}
10495
10496/// 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.
10497#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10498#[non_exhaustive]
10499pub struct PickOfTheDayLedgerUncommittedEntry {
10500    pub state: String,
10501    /// ET product day the pick belongs to (YYYY-MM-DD).
10502    pub pick_date: String,
10503    /// Deprecated compatibility daily release slot; use pick_id for identity and publication_order for scheduling.
10504    pub pick_rank: i64,
10505    /// Always true: this pick has no commitment and never will.
10506    pub pre_commitment: bool,
10507    /// How the pick settled, or pending.
10508    pub outcome: Outcome,
10509    /// 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.
10510    #[serde(default, skip_serializing_if = "Option::is_none")]
10511    pub withdrawal_reason: Option<WithdrawalReason>,
10512    /// Frozen matchup, for a reader.
10513    #[serde(default, skip_serializing_if = "Option::is_none")]
10514    pub matchup: Option<String>,
10515    /// Frozen canonical sport bucket (for example Basketball or MMA), not the exact public league identity; the archive owns that.
10516    #[serde(default, skip_serializing_if = "Option::is_none")]
10517    pub category: Option<String>,
10518    /// 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.
10519    #[serde(default)]
10520    pub resolved_at: Option<String>,
10521    /// 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.
10522    #[serde(default)]
10523    pub payload: Option<PickOfTheDayUncommittedPayload>,
10524    /// The pick's stable public page, `https://0xinsider.com/pick-of-the-day/picks/{pick_id}`.
10525    pub permalink: String,
10526    /// Stable pick row identity as decimal text. Never use a quality rank as identity.
10527    pub pick_id: String,
10528    /// Compatibility release slot. No quality claim; historic scheduling order is retained.
10529    pub publication_order: i64,
10530    /// Viewer-independent free selection designation. New rows store it explicitly; historic null storage uses the original free slot.
10531    pub is_free_selection: bool,
10532    /// 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.
10533    #[serde(default)]
10534    pub supersedes_pick_id: Option<String>,
10535}
10536
10537#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10538#[non_exhaustive]
10539pub struct PickOfTheDayLockedPicksItem {
10540    pub pick_rank: i64,
10541    pub required_tier: String,
10542}
10543
10544/// 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.
10545#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10546#[non_exhaustive]
10547pub struct PickOfTheDayNoEntitledPicks {
10548    /// Only locked ranks are published for this account.
10549    pub state: String,
10550    /// Current product date in America/New_York (YYYY-MM-DD).
10551    pub pick_date: String,
10552    /// Empty: no entitled proof-readable picks are returned.
10553    pub picks: Vec<PickOfTheDay>,
10554    /// Zero entitled proof-readable picks.
10555    pub pick_count: i64,
10556    /// Unauthorized unresolved published or scheduled ranks. Contains no game, provider identity, price, or identifying clock. Pro may upgrade to Max to open these ranks.
10557    pub locked_picks: Vec<PickOfTheDayNoEntitledPicksLockedPicksItem>,
10558    /// Actionable status, including Upgrade to Max when only locked ranks are published.
10559    pub message: String,
10560    /// 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.
10561    #[serde(default, skip_serializing_if = "Option::is_none")]
10562    pub scheduled_picks: Option<Vec<ScheduledPickSlot>>,
10563    /// 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.
10564    #[serde(default)]
10565    pub supersedes_pick_id: Option<String>,
10566}
10567
10568#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10569#[non_exhaustive]
10570pub struct PickOfTheDayNoEntitledPicksLockedPicksItem {
10571    pub pick_rank: i64,
10572    pub required_tier: String,
10573}
10574
10575/// 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.
10576#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10577#[non_exhaustive]
10578pub struct PickOfTheDayQualifyingExpert {
10579    /// Trader wallet address.
10580    pub address: String,
10581    /// Provider display name, or null for an unnamed wallet.
10582    #[serde(default)]
10583    pub name: Option<String>,
10584    /// Recorded trader grade. Public V1 preserves its S/A compatibility projection.
10585    #[serde(default)]
10586    pub grade: Option<String>,
10587    /// 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.
10588    pub canonical_category: String,
10589    /// 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.
10590    #[serde(default)]
10591    pub win_rate: Option<f64>,
10592    /// Number of settled markets behind win_rate; null when not measured.
10593    #[serde(default)]
10594    pub n_resolved: Option<i64>,
10595    /// Recorded Polymarket position value on the backed outcome, in USD. It can change after this snapshot.
10596    pub position_usd: f64,
10597    /// Recorded position value on the other outcome of this market, in USD. Omitted when not recorded; zero is a measured value.
10598    #[serde(default, skip_serializing_if = "Option::is_none")]
10599    pub opposite_position_usd: Option<f64>,
10600    /// Timestamp of the recorded trader statistics.
10601    pub stats_computed_at: String,
10602}
10603
10604#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10605#[non_exhaustive]
10606pub struct PickOfTheDayStats {
10607    pub categories: Vec<PickOfTheDayStatsCategoriesItem>,
10608    pub days: Vec<PickOfTheDayStatsDaysItem>,
10609    pub hit_rate: PickOfTheDayHitRate,
10610    pub market_expectations: PickOfTheDayStatsMarketExpectations,
10611    pub market_types: Vec<PickOfTheDayStatsMarketTypesItem>,
10612    pub months: Vec<PickOfTheDayStatsMonthsItem>,
10613    pub outcome_stats: PickOfTheDayStatsOutcomeStats,
10614    pub price_bands: Vec<PickOfTheDayStatsPriceBandsItem>,
10615    pub records: PickOfTheDayStatsRecords,
10616    pub sports: Vec<PickOfTheDayStatsSportsItem>,
10617    pub streaks: PickOfTheDayStatsStreaks,
10618    pub tiers: Vec<PickOfTheDayStatsTiersItem>,
10619    pub total_sides: Vec<PickOfTheDayStatsTotalSidesItem>,
10620    pub voids: Vec<PickOfTheDayStatsVoidsItem>,
10621}
10622
10623#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10624#[non_exhaustive]
10625pub struct PickOfTheDayStatsCategoriesItem {
10626    #[serde(default, skip_serializing_if = "Option::is_none")]
10627    pub canonical_category: Option<String>,
10628    #[serde(default, skip_serializing_if = "Option::is_none")]
10629    pub clv_avg_display: Option<String>,
10630    #[serde(default, skip_serializing_if = "Option::is_none")]
10631    pub clv_avg_pct: Option<f64>,
10632    #[serde(default, skip_serializing_if = "Option::is_none")]
10633    pub clv_avg_pp: Option<f64>,
10634    #[serde(default, skip_serializing_if = "Option::is_none")]
10635    pub clv_avg_pp_display: Option<String>,
10636    pub clv_measured: i64,
10637    #[serde(default, skip_serializing_if = "Option::is_none")]
10638    pub edge_display: Option<String>,
10639    #[serde(default, skip_serializing_if = "Option::is_none")]
10640    pub edge_pp: Option<f64>,
10641    pub key: String,
10642    pub label: String,
10643    pub losses: i64,
10644    #[serde(default, skip_serializing_if = "Option::is_none")]
10645    pub net_profit_display: Option<String>,
10646    #[serde(default, skip_serializing_if = "Option::is_none")]
10647    pub net_profit_usd: Option<f64>,
10648    pub pending: i64,
10649    pub picks: i64,
10650    pub priced_decided: i64,
10651    #[serde(default, skip_serializing_if = "Option::is_none")]
10652    pub priced_in_display: Option<String>,
10653    #[serde(default, skip_serializing_if = "Option::is_none")]
10654    pub priced_in_pct: Option<f64>,
10655    #[serde(default, skip_serializing_if = "Option::is_none")]
10656    pub roi_display: Option<String>,
10657    #[serde(default, skip_serializing_if = "Option::is_none")]
10658    pub roi_pct: Option<f64>,
10659    pub settled: i64,
10660    pub small_sample: bool,
10661    pub staked_usd: f64,
10662    #[serde(default, skip_serializing_if = "Option::is_none")]
10663    pub unit_score: Option<f64>,
10664    #[serde(default, skip_serializing_if = "Option::is_none")]
10665    pub unit_score_display: Option<String>,
10666    pub void: i64,
10667    #[serde(default, skip_serializing_if = "Option::is_none")]
10668    pub win_rate_display: Option<String>,
10669    #[serde(default, skip_serializing_if = "Option::is_none")]
10670    pub win_rate_pct: Option<f64>,
10671    pub wins: i64,
10672}
10673
10674#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10675#[non_exhaustive]
10676pub struct PickOfTheDayStatsDaysItem {
10677    pub date: String,
10678    pub losses: i64,
10679    #[serde(default, skip_serializing_if = "Option::is_none")]
10680    pub net_profit_display: Option<String>,
10681    #[serde(default, skip_serializing_if = "Option::is_none")]
10682    pub net_profit_usd: Option<f64>,
10683    pub pending: i64,
10684    pub picks: i64,
10685    #[serde(default, skip_serializing_if = "Option::is_none")]
10686    pub sweep: Option<Sweep>,
10687    #[serde(default, skip_serializing_if = "Option::is_none")]
10688    pub unit_score: Option<f64>,
10689    #[serde(default, skip_serializing_if = "Option::is_none")]
10690    pub unit_score_display: Option<String>,
10691    pub void: i64,
10692    pub wins: i64,
10693}
10694
10695#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10696#[non_exhaustive]
10697pub struct PickOfTheDayStatsMarketExpectations {
10698    pub as_of_date: String,
10699    pub price_basis: String,
10700    pub timezone: String,
10701    pub windows: Vec<PickOfTheDayStatsMarketExpectationsWindowsItem>,
10702}
10703
10704#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10705#[non_exhaustive]
10706pub struct PickOfTheDayStatsMarketExpectationsWindowsItem {
10707    #[serde(default)]
10708    pub clv_avg_display: Option<String>,
10709    #[serde(default)]
10710    pub clv_avg_pct: Option<f64>,
10711    #[serde(default)]
10712    pub clv_avg_pp: Option<f64>,
10713    #[serde(default)]
10714    pub clv_avg_pp_display: Option<String>,
10715    pub clv_measured: i64,
10716    pub clv_missing: i64,
10717    #[serde(default)]
10718    pub expected_wins: Option<f64>,
10719    #[serde(default)]
10720    pub expected_wins_display: Option<String>,
10721    #[serde(default)]
10722    pub from_date: Option<String>,
10723    pub key: String,
10724    pub label: String,
10725    pub numeric_unavailable: bool,
10726    pub priced_decided: i64,
10727    pub through_date: String,
10728    #[serde(default)]
10729    pub units: Option<f64>,
10730    #[serde(default)]
10731    pub units_display: Option<String>,
10732    #[serde(default)]
10733    pub units_z: Option<f64>,
10734    #[serde(default)]
10735    pub units_z_display: Option<String>,
10736    pub unpriced_decided: i64,
10737    pub wins: i64,
10738    #[serde(default)]
10739    pub wins_z: Option<f64>,
10740    #[serde(default)]
10741    pub wins_z_display: Option<String>,
10742}
10743
10744#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10745#[non_exhaustive]
10746pub struct PickOfTheDayStatsMarketTypesItem {
10747    #[serde(default, skip_serializing_if = "Option::is_none")]
10748    pub canonical_category: Option<String>,
10749    #[serde(default, skip_serializing_if = "Option::is_none")]
10750    pub clv_avg_display: Option<String>,
10751    #[serde(default, skip_serializing_if = "Option::is_none")]
10752    pub clv_avg_pct: Option<f64>,
10753    #[serde(default, skip_serializing_if = "Option::is_none")]
10754    pub clv_avg_pp: Option<f64>,
10755    #[serde(default, skip_serializing_if = "Option::is_none")]
10756    pub clv_avg_pp_display: Option<String>,
10757    pub clv_measured: i64,
10758    #[serde(default, skip_serializing_if = "Option::is_none")]
10759    pub edge_display: Option<String>,
10760    #[serde(default, skip_serializing_if = "Option::is_none")]
10761    pub edge_pp: Option<f64>,
10762    pub key: String,
10763    pub label: String,
10764    pub losses: i64,
10765    #[serde(default, skip_serializing_if = "Option::is_none")]
10766    pub net_profit_display: Option<String>,
10767    #[serde(default, skip_serializing_if = "Option::is_none")]
10768    pub net_profit_usd: Option<f64>,
10769    pub pending: i64,
10770    pub picks: i64,
10771    pub priced_decided: i64,
10772    #[serde(default, skip_serializing_if = "Option::is_none")]
10773    pub priced_in_display: Option<String>,
10774    #[serde(default, skip_serializing_if = "Option::is_none")]
10775    pub priced_in_pct: Option<f64>,
10776    #[serde(default, skip_serializing_if = "Option::is_none")]
10777    pub roi_display: Option<String>,
10778    #[serde(default, skip_serializing_if = "Option::is_none")]
10779    pub roi_pct: Option<f64>,
10780    pub settled: i64,
10781    pub small_sample: bool,
10782    pub staked_usd: f64,
10783    #[serde(default, skip_serializing_if = "Option::is_none")]
10784    pub unit_score: Option<f64>,
10785    #[serde(default, skip_serializing_if = "Option::is_none")]
10786    pub unit_score_display: Option<String>,
10787    pub void: i64,
10788    #[serde(default, skip_serializing_if = "Option::is_none")]
10789    pub win_rate_display: Option<String>,
10790    #[serde(default, skip_serializing_if = "Option::is_none")]
10791    pub win_rate_pct: Option<f64>,
10792    pub wins: i64,
10793}
10794
10795#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10796#[non_exhaustive]
10797pub struct PickOfTheDayStatsMonthsItem {
10798    #[serde(default, skip_serializing_if = "Option::is_none")]
10799    pub canonical_category: Option<String>,
10800    #[serde(default, skip_serializing_if = "Option::is_none")]
10801    pub clv_avg_display: Option<String>,
10802    #[serde(default, skip_serializing_if = "Option::is_none")]
10803    pub clv_avg_pct: Option<f64>,
10804    #[serde(default, skip_serializing_if = "Option::is_none")]
10805    pub clv_avg_pp: Option<f64>,
10806    #[serde(default, skip_serializing_if = "Option::is_none")]
10807    pub clv_avg_pp_display: Option<String>,
10808    pub clv_measured: i64,
10809    #[serde(default, skip_serializing_if = "Option::is_none")]
10810    pub edge_display: Option<String>,
10811    #[serde(default, skip_serializing_if = "Option::is_none")]
10812    pub edge_pp: Option<f64>,
10813    pub key: String,
10814    pub label: String,
10815    pub losses: i64,
10816    #[serde(default, skip_serializing_if = "Option::is_none")]
10817    pub net_profit_display: Option<String>,
10818    #[serde(default, skip_serializing_if = "Option::is_none")]
10819    pub net_profit_usd: Option<f64>,
10820    pub pending: i64,
10821    pub picks: i64,
10822    pub priced_decided: i64,
10823    #[serde(default, skip_serializing_if = "Option::is_none")]
10824    pub priced_in_display: Option<String>,
10825    #[serde(default, skip_serializing_if = "Option::is_none")]
10826    pub priced_in_pct: Option<f64>,
10827    #[serde(default, skip_serializing_if = "Option::is_none")]
10828    pub roi_display: Option<String>,
10829    #[serde(default, skip_serializing_if = "Option::is_none")]
10830    pub roi_pct: Option<f64>,
10831    pub settled: i64,
10832    pub small_sample: bool,
10833    pub staked_usd: f64,
10834    #[serde(default, skip_serializing_if = "Option::is_none")]
10835    pub unit_score: Option<f64>,
10836    #[serde(default, skip_serializing_if = "Option::is_none")]
10837    pub unit_score_display: Option<String>,
10838    pub void: i64,
10839    #[serde(default, skip_serializing_if = "Option::is_none")]
10840    pub win_rate_display: Option<String>,
10841    #[serde(default, skip_serializing_if = "Option::is_none")]
10842    pub win_rate_pct: Option<f64>,
10843    pub wins: i64,
10844}
10845
10846#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10847#[non_exhaustive]
10848pub struct PickOfTheDayStatsOutcomeStats {
10849    pub concentration: PickOfTheDayStatsOutcomeStatsConcentration,
10850    pub drawdown: PickOfTheDayStatsOutcomeStatsDrawdown,
10851    pub profit_factor: PickOfTheDayStatsOutcomeStatsProfitFactor,
10852    pub rolling: Vec<PickOfTheDayStatsOutcomeStatsRollingItem>,
10853}
10854
10855#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10856#[non_exhaustive]
10857pub struct PickOfTheDayStatsOutcomeStatsConcentration {
10858    pub positive_wins: i64,
10859    pub remaining_valued_decided: i64,
10860    pub removed_wins: i64,
10861    #[serde(default)]
10862    pub roi_without_top_wins_display: Option<String>,
10863    #[serde(default)]
10864    pub roi_without_top_wins_pct: Option<f64>,
10865    pub target_wins: i64,
10866    #[serde(default)]
10867    pub top_wins_share_display: Option<String>,
10868    #[serde(default)]
10869    pub top_wins_share_pct: Option<f64>,
10870    pub valued_decided: i64,
10871}
10872
10873#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10874#[non_exhaustive]
10875pub struct PickOfTheDayStatsOutcomeStatsDrawdown {
10876    pub completed_days: i64,
10877    #[serde(default)]
10878    pub current_days_below_peak: Option<i64>,
10879    #[serde(default)]
10880    pub current_drawdown_display: Option<String>,
10881    #[serde(default)]
10882    pub current_drawdown_units: Option<f64>,
10883    #[serde(default)]
10884    pub days_below_peak: Option<i64>,
10885    pub excluded_days: i64,
10886    #[serde(default)]
10887    pub from_date: Option<String>,
10888    #[serde(default)]
10889    pub longest_days_below_peak: Option<i64>,
10890    #[serde(default)]
10891    pub longest_recovery_days: Option<i64>,
10892    #[serde(default)]
10893    pub max_drawdown_display: Option<String>,
10894    #[serde(default)]
10895    pub max_drawdown_units: Option<f64>,
10896    #[serde(default)]
10897    pub peak_date: Option<String>,
10898    #[serde(default)]
10899    pub peak_net_profit_usd: Option<f64>,
10900    #[serde(default)]
10901    pub through_date: Option<String>,
10902}
10903
10904#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10905#[non_exhaustive]
10906pub struct PickOfTheDayStatsOutcomeStatsProfitFactor {
10907    #[serde(default)]
10908    pub display: Option<String>,
10909    #[serde(default)]
10910    pub gross_loss_usd: Option<f64>,
10911    #[serde(default)]
10912    pub gross_profit_usd: Option<f64>,
10913    pub state: PickOfTheDayStatsOutcomeStatsProfitFactorState,
10914    #[serde(default)]
10915    pub value: Option<f64>,
10916    pub valued_decided: i64,
10917}
10918
10919/// A value this release does not know is kept in `Other`, so a new value never fails a response.
10920#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
10921#[non_exhaustive]
10922pub enum PickOfTheDayStatsOutcomeStatsProfitFactorState {
10923    /// `empty`
10924    #[serde(rename = "empty")]
10925    Empty,
10926    /// `measured`
10927    #[serde(rename = "measured")]
10928    Measured,
10929    /// `no_losses`
10930    #[serde(rename = "no_losses")]
10931    NoLosses,
10932    /// `numeric_unavailable`
10933    #[serde(rename = "numeric_unavailable")]
10934    NumericUnavailable,
10935    /// A value this release does not know, kept as sent.
10936    #[serde(untagged)]
10937    Other(String),
10938}
10939
10940impl PickOfTheDayStatsOutcomeStatsProfitFactorState {
10941    /// The value as the API spells it.
10942    pub fn as_str(&self) -> &str {
10943        match self {
10944            Self::Empty => "empty",
10945            Self::Measured => "measured",
10946            Self::NoLosses => "no_losses",
10947            Self::NumericUnavailable => "numeric_unavailable",
10948            Self::Other(value) => value,
10949        }
10950    }
10951}
10952
10953impl From<&str> for PickOfTheDayStatsOutcomeStatsProfitFactorState {
10954    fn from(value: &str) -> Self {
10955        match value {
10956            "empty" => Self::Empty,
10957            "measured" => Self::Measured,
10958            "no_losses" => Self::NoLosses,
10959            "numeric_unavailable" => Self::NumericUnavailable,
10960            other => Self::Other(other.to_owned()),
10961        }
10962    }
10963}
10964
10965impl std::fmt::Display for PickOfTheDayStatsOutcomeStatsProfitFactorState {
10966    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
10967        f.write_str(self.as_str())
10968    }
10969}
10970
10971impl AsRef<str> for PickOfTheDayStatsOutcomeStatsProfitFactorState {
10972    fn as_ref(&self) -> &str {
10973        self.as_str()
10974    }
10975}
10976
10977#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10978#[non_exhaustive]
10979pub struct PickOfTheDayStatsOutcomeStatsRollingItem {
10980    #[serde(default)]
10981    pub from_date: Option<String>,
10982    pub losses: i64,
10983    #[serde(default)]
10984    pub roi_display: Option<String>,
10985    #[serde(default)]
10986    pub roi_pct: Option<f64>,
10987    #[serde(default)]
10988    pub through_date: Option<String>,
10989    #[serde(default)]
10990    pub units: Option<f64>,
10991    #[serde(default)]
10992    pub units_display: Option<String>,
10993    pub valued_decided: i64,
10994    #[serde(default)]
10995    pub win_rate_display: Option<String>,
10996    #[serde(default)]
10997    pub win_rate_pct: Option<f64>,
10998    pub window_size: i64,
10999    pub wins: i64,
11000}
11001
11002#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11003#[non_exhaustive]
11004pub struct PickOfTheDayStatsPriceBandsItem {
11005    #[serde(default, skip_serializing_if = "Option::is_none")]
11006    pub canonical_category: Option<String>,
11007    #[serde(default, skip_serializing_if = "Option::is_none")]
11008    pub clv_avg_display: Option<String>,
11009    #[serde(default, skip_serializing_if = "Option::is_none")]
11010    pub clv_avg_pct: Option<f64>,
11011    #[serde(default, skip_serializing_if = "Option::is_none")]
11012    pub clv_avg_pp: Option<f64>,
11013    #[serde(default, skip_serializing_if = "Option::is_none")]
11014    pub clv_avg_pp_display: Option<String>,
11015    pub clv_measured: i64,
11016    #[serde(default, skip_serializing_if = "Option::is_none")]
11017    pub edge_display: Option<String>,
11018    #[serde(default, skip_serializing_if = "Option::is_none")]
11019    pub edge_pp: Option<f64>,
11020    pub key: String,
11021    pub label: String,
11022    pub losses: i64,
11023    #[serde(default, skip_serializing_if = "Option::is_none")]
11024    pub net_profit_display: Option<String>,
11025    #[serde(default, skip_serializing_if = "Option::is_none")]
11026    pub net_profit_usd: Option<f64>,
11027    pub pending: i64,
11028    pub picks: i64,
11029    pub priced_decided: i64,
11030    #[serde(default, skip_serializing_if = "Option::is_none")]
11031    pub priced_in_display: Option<String>,
11032    #[serde(default, skip_serializing_if = "Option::is_none")]
11033    pub priced_in_pct: Option<f64>,
11034    #[serde(default, skip_serializing_if = "Option::is_none")]
11035    pub roi_display: Option<String>,
11036    #[serde(default, skip_serializing_if = "Option::is_none")]
11037    pub roi_pct: Option<f64>,
11038    pub settled: i64,
11039    pub small_sample: bool,
11040    pub staked_usd: f64,
11041    #[serde(default, skip_serializing_if = "Option::is_none")]
11042    pub unit_score: Option<f64>,
11043    #[serde(default, skip_serializing_if = "Option::is_none")]
11044    pub unit_score_display: Option<String>,
11045    pub void: i64,
11046    #[serde(default, skip_serializing_if = "Option::is_none")]
11047    pub win_rate_display: Option<String>,
11048    #[serde(default, skip_serializing_if = "Option::is_none")]
11049    pub win_rate_pct: Option<f64>,
11050    pub wins: i64,
11051}
11052
11053#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11054#[non_exhaustive]
11055pub struct PickOfTheDayStatsRecords {
11056    #[serde(default, skip_serializing_if = "Option::is_none")]
11057    pub best_day: Option<PickOfTheDayStatsRecordsBestDay>,
11058    #[serde(default, skip_serializing_if = "Option::is_none")]
11059    pub biggest_win: Option<PickOfTheDayStatsRecordsBiggestWin>,
11060    #[serde(default, skip_serializing_if = "Option::is_none")]
11061    pub longest_losing_day_streak: Option<PickOfTheDayStatsRecordsLongestLosingDayStreak>,
11062    #[serde(default, skip_serializing_if = "Option::is_none")]
11063    pub longest_winning_day_streak: Option<PickOfTheDayStatsRecordsLongestWinningDayStreak>,
11064    pub sweeps: PickOfTheDayStatsRecordsSweeps,
11065    #[serde(default, skip_serializing_if = "Option::is_none")]
11066    pub winning_days: Option<PickOfTheDayStatsRecordsWinningDays>,
11067    #[serde(default, skip_serializing_if = "Option::is_none")]
11068    pub worst_day: Option<PickOfTheDayStatsRecordsWorstDay>,
11069}
11070
11071#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11072#[non_exhaustive]
11073pub struct PickOfTheDayStatsRecordsBestDay {
11074    pub date: String,
11075    pub date_display: String,
11076    pub losses: i64,
11077    pub net_profit_display: String,
11078    pub net_profit_usd: f64,
11079    pub picks: i64,
11080    pub wins: i64,
11081}
11082
11083#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11084#[non_exhaustive]
11085pub struct PickOfTheDayStatsRecordsBiggestWin {
11086    pub category: String,
11087    pub date: String,
11088    pub date_display: String,
11089    pub matchup: String,
11090    pub net_profit_display: String,
11091    pub net_profit_usd: f64,
11092}
11093
11094#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11095#[non_exhaustive]
11096pub struct PickOfTheDayStatsRecordsLongestLosingDayStreak {
11097    pub days: i64,
11098    pub end_date: String,
11099    pub net_profit_display: String,
11100    pub net_profit_usd: f64,
11101    pub range_display: String,
11102    pub start_date: String,
11103}
11104
11105#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11106#[non_exhaustive]
11107pub struct PickOfTheDayStatsRecordsLongestWinningDayStreak {
11108    pub days: i64,
11109    pub end_date: String,
11110    pub net_profit_display: String,
11111    pub net_profit_usd: f64,
11112    pub range_display: String,
11113    pub start_date: String,
11114}
11115
11116#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11117#[non_exhaustive]
11118pub struct PickOfTheDayStatsRecordsSweeps {
11119    pub clean_sweeps: i64,
11120    #[serde(default, skip_serializing_if = "Option::is_none")]
11121    pub latest_clean_sweep: Option<PickOfTheDayStatsRecordsSweepsLatestCleanSweep>,
11122    #[serde(default, skip_serializing_if = "Option::is_none")]
11123    pub latest_wipeout: Option<PickOfTheDayStatsRecordsSweepsLatestWipeout>,
11124    pub min_decided: i64,
11125    pub wipeouts: i64,
11126}
11127
11128#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11129#[non_exhaustive]
11130pub struct PickOfTheDayStatsRecordsSweepsLatestCleanSweep {
11131    pub date: String,
11132    pub date_display: String,
11133    pub losses: i64,
11134    pub wins: i64,
11135}
11136
11137#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11138#[non_exhaustive]
11139pub struct PickOfTheDayStatsRecordsSweepsLatestWipeout {
11140    pub date: String,
11141    pub date_display: String,
11142    pub losses: i64,
11143    pub wins: i64,
11144}
11145
11146#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11147#[non_exhaustive]
11148pub struct PickOfTheDayStatsRecordsWinningDays {
11149    pub flat: i64,
11150    pub losing: i64,
11151    pub settled: i64,
11152    pub winning: i64,
11153    pub winning_pct: f64,
11154    pub winning_pct_display: String,
11155}
11156
11157#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11158#[non_exhaustive]
11159pub struct PickOfTheDayStatsRecordsWorstDay {
11160    pub date: String,
11161    pub date_display: String,
11162    pub losses: i64,
11163    pub net_profit_display: String,
11164    pub net_profit_usd: f64,
11165    pub picks: i64,
11166    pub wins: i64,
11167}
11168
11169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11170#[non_exhaustive]
11171pub struct PickOfTheDayStatsSportsItem {
11172    #[serde(default, skip_serializing_if = "Option::is_none")]
11173    pub canonical_category: Option<String>,
11174    #[serde(default, skip_serializing_if = "Option::is_none")]
11175    pub clv_avg_display: Option<String>,
11176    #[serde(default, skip_serializing_if = "Option::is_none")]
11177    pub clv_avg_pct: Option<f64>,
11178    #[serde(default, skip_serializing_if = "Option::is_none")]
11179    pub clv_avg_pp: Option<f64>,
11180    #[serde(default, skip_serializing_if = "Option::is_none")]
11181    pub clv_avg_pp_display: Option<String>,
11182    pub clv_measured: i64,
11183    #[serde(default, skip_serializing_if = "Option::is_none")]
11184    pub edge_display: Option<String>,
11185    #[serde(default, skip_serializing_if = "Option::is_none")]
11186    pub edge_pp: Option<f64>,
11187    pub key: String,
11188    pub label: String,
11189    pub losses: i64,
11190    #[serde(default, skip_serializing_if = "Option::is_none")]
11191    pub net_profit_display: Option<String>,
11192    #[serde(default, skip_serializing_if = "Option::is_none")]
11193    pub net_profit_usd: Option<f64>,
11194    pub pending: i64,
11195    pub picks: i64,
11196    pub priced_decided: i64,
11197    #[serde(default, skip_serializing_if = "Option::is_none")]
11198    pub priced_in_display: Option<String>,
11199    #[serde(default, skip_serializing_if = "Option::is_none")]
11200    pub priced_in_pct: Option<f64>,
11201    #[serde(default, skip_serializing_if = "Option::is_none")]
11202    pub roi_display: Option<String>,
11203    #[serde(default, skip_serializing_if = "Option::is_none")]
11204    pub roi_pct: Option<f64>,
11205    pub settled: i64,
11206    pub small_sample: bool,
11207    pub staked_usd: f64,
11208    #[serde(default, skip_serializing_if = "Option::is_none")]
11209    pub unit_score: Option<f64>,
11210    #[serde(default, skip_serializing_if = "Option::is_none")]
11211    pub unit_score_display: Option<String>,
11212    pub void: i64,
11213    #[serde(default, skip_serializing_if = "Option::is_none")]
11214    pub win_rate_display: Option<String>,
11215    #[serde(default, skip_serializing_if = "Option::is_none")]
11216    pub win_rate_pct: Option<f64>,
11217    pub wins: i64,
11218}
11219
11220#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11221#[non_exhaustive]
11222pub struct PickOfTheDayStatsStreaks {
11223    #[serde(default, skip_serializing_if = "Option::is_none")]
11224    pub current: Option<i64>,
11225    #[serde(default, skip_serializing_if = "Option::is_none")]
11226    pub current_day: Option<i64>,
11227    #[serde(default, skip_serializing_if = "Option::is_none")]
11228    pub current_day_display: Option<String>,
11229    #[serde(default, skip_serializing_if = "Option::is_none")]
11230    pub current_display: Option<String>,
11231    pub longest_loss: i64,
11232    pub longest_win: i64,
11233}
11234
11235#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11236#[non_exhaustive]
11237pub struct PickOfTheDayStatsTiersItem {
11238    #[serde(default, skip_serializing_if = "Option::is_none")]
11239    pub canonical_category: Option<String>,
11240    #[serde(default, skip_serializing_if = "Option::is_none")]
11241    pub clv_avg_display: Option<String>,
11242    #[serde(default, skip_serializing_if = "Option::is_none")]
11243    pub clv_avg_pct: Option<f64>,
11244    #[serde(default, skip_serializing_if = "Option::is_none")]
11245    pub clv_avg_pp: Option<f64>,
11246    #[serde(default, skip_serializing_if = "Option::is_none")]
11247    pub clv_avg_pp_display: Option<String>,
11248    pub clv_measured: i64,
11249    #[serde(default, skip_serializing_if = "Option::is_none")]
11250    pub edge_display: Option<String>,
11251    #[serde(default, skip_serializing_if = "Option::is_none")]
11252    pub edge_pp: Option<f64>,
11253    pub key: String,
11254    pub label: String,
11255    pub losses: i64,
11256    #[serde(default, skip_serializing_if = "Option::is_none")]
11257    pub net_profit_display: Option<String>,
11258    #[serde(default, skip_serializing_if = "Option::is_none")]
11259    pub net_profit_usd: Option<f64>,
11260    pub pending: i64,
11261    pub picks: i64,
11262    pub priced_decided: i64,
11263    #[serde(default, skip_serializing_if = "Option::is_none")]
11264    pub priced_in_display: Option<String>,
11265    #[serde(default, skip_serializing_if = "Option::is_none")]
11266    pub priced_in_pct: Option<f64>,
11267    #[serde(default, skip_serializing_if = "Option::is_none")]
11268    pub roi_display: Option<String>,
11269    #[serde(default, skip_serializing_if = "Option::is_none")]
11270    pub roi_pct: Option<f64>,
11271    pub settled: i64,
11272    pub small_sample: bool,
11273    pub staked_usd: f64,
11274    #[serde(default, skip_serializing_if = "Option::is_none")]
11275    pub unit_score: Option<f64>,
11276    #[serde(default, skip_serializing_if = "Option::is_none")]
11277    pub unit_score_display: Option<String>,
11278    pub void: i64,
11279    #[serde(default, skip_serializing_if = "Option::is_none")]
11280    pub win_rate_display: Option<String>,
11281    #[serde(default, skip_serializing_if = "Option::is_none")]
11282    pub win_rate_pct: Option<f64>,
11283    pub wins: i64,
11284}
11285
11286#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11287#[non_exhaustive]
11288pub struct PickOfTheDayStatsTotalSidesItem {
11289    #[serde(default, skip_serializing_if = "Option::is_none")]
11290    pub canonical_category: Option<String>,
11291    #[serde(default, skip_serializing_if = "Option::is_none")]
11292    pub clv_avg_display: Option<String>,
11293    #[serde(default, skip_serializing_if = "Option::is_none")]
11294    pub clv_avg_pct: Option<f64>,
11295    #[serde(default, skip_serializing_if = "Option::is_none")]
11296    pub clv_avg_pp: Option<f64>,
11297    #[serde(default, skip_serializing_if = "Option::is_none")]
11298    pub clv_avg_pp_display: Option<String>,
11299    pub clv_measured: i64,
11300    #[serde(default, skip_serializing_if = "Option::is_none")]
11301    pub edge_display: Option<String>,
11302    #[serde(default, skip_serializing_if = "Option::is_none")]
11303    pub edge_pp: Option<f64>,
11304    pub key: String,
11305    pub label: String,
11306    pub losses: i64,
11307    #[serde(default, skip_serializing_if = "Option::is_none")]
11308    pub net_profit_display: Option<String>,
11309    #[serde(default, skip_serializing_if = "Option::is_none")]
11310    pub net_profit_usd: Option<f64>,
11311    pub pending: i64,
11312    pub picks: i64,
11313    pub priced_decided: i64,
11314    #[serde(default, skip_serializing_if = "Option::is_none")]
11315    pub priced_in_display: Option<String>,
11316    #[serde(default, skip_serializing_if = "Option::is_none")]
11317    pub priced_in_pct: Option<f64>,
11318    #[serde(default, skip_serializing_if = "Option::is_none")]
11319    pub roi_display: Option<String>,
11320    #[serde(default, skip_serializing_if = "Option::is_none")]
11321    pub roi_pct: Option<f64>,
11322    pub settled: i64,
11323    pub small_sample: bool,
11324    pub staked_usd: f64,
11325    #[serde(default, skip_serializing_if = "Option::is_none")]
11326    pub unit_score: Option<f64>,
11327    #[serde(default, skip_serializing_if = "Option::is_none")]
11328    pub unit_score_display: Option<String>,
11329    pub void: i64,
11330    #[serde(default, skip_serializing_if = "Option::is_none")]
11331    pub win_rate_display: Option<String>,
11332    #[serde(default, skip_serializing_if = "Option::is_none")]
11333    pub win_rate_pct: Option<f64>,
11334    pub wins: i64,
11335}
11336
11337#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11338#[non_exhaustive]
11339pub struct PickOfTheDayStatsVoidsItem {
11340    #[serde(default, skip_serializing_if = "Option::is_none")]
11341    pub backed_price: Option<f64>,
11342    #[serde(default, skip_serializing_if = "Option::is_none")]
11343    pub backed_side: Option<String>,
11344    #[serde(default, skip_serializing_if = "Option::is_none")]
11345    pub category: Option<String>,
11346    #[serde(default, skip_serializing_if = "Option::is_none")]
11347    pub matchup: Option<String>,
11348    pub pick_date: String,
11349    pub pick_id: String,
11350    pub pick_rank: i64,
11351}
11352
11353/// 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.
11354#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11355#[non_exhaustive]
11356pub struct PickOfTheDayUncommittedPayload {
11357    /// 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.
11358    pub backed_price: String,
11359    /// Provider condition id of the backed market.
11360    pub condition_id: String,
11361    /// 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.
11362    #[serde(default)]
11363    pub kickoff: Option<String>,
11364    /// ET product day (YYYY-MM-DD).
11365    pub pick_date: String,
11366    /// Index of the backed outcome within the market.
11367    pub pick_outcome_index: i64,
11368    /// Frozen display label of the backed outcome.
11369    pub pick_outcome_label: String,
11370    /// 1-based daily slot.
11371    pub pick_rank: i64,
11372    /// Provider platform. Always polymarket.
11373    pub platform: String,
11374}
11375
11376/// 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.
11377#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11378#[non_exhaustive]
11379pub struct PickSportsContext {
11380    /// League or competition display name (e.g. "Premier League").
11381    #[serde(default)]
11382    pub league_name: Option<String>,
11383    /// 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.
11384    #[serde(default, skip_serializing_if = "Option::is_none")]
11385    pub competition_label: Option<String>,
11386    /// League logo URL (provider-owned).
11387    #[serde(default)]
11388    pub league_logo: Option<String>,
11389    /// The team mapped to the market's YES outcome, or the parent-event home/first team when event_matchup is true.
11390    #[serde(default)]
11391    pub yes_team: Option<PickSportsTeam>,
11392    /// The team mapped to the market's NO outcome, or the parent-event away/second team when event_matchup is true.
11393    #[serde(default)]
11394    pub no_team: Option<PickSportsTeam>,
11395    /// Provider game identifier (Polymarket Gamma gameId); omitted when the provider supplies none.
11396    #[serde(default, skip_serializing_if = "Option::is_none")]
11397    pub game_id: Option<i64>,
11398    /// 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.
11399    pub event_matchup: bool,
11400    /// 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).
11401    #[serde(default, skip_serializing_if = "Option::is_none")]
11402    pub event_subject_team: Option<PickSportsTeam>,
11403    /// 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.
11404    #[serde(default, skip_serializing_if = "Option::is_none")]
11405    pub matchup_title: Option<String>,
11406}
11407
11408/// 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.
11409#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11410#[non_exhaustive]
11411pub struct PickSportsTeam {
11412    /// Team display label as it appears on the market outcome (e.g. "Portugal").
11413    #[serde(default)]
11414    pub label: Option<String>,
11415    /// Abbreviated team label (e.g. "POR").
11416    #[serde(default)]
11417    pub short_label: Option<String>,
11418    /// 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.
11419    #[serde(default)]
11420    pub full_name: Option<String>,
11421    /// Provider team identifier (Polymarket /teams id).
11422    #[serde(default)]
11423    pub provider_id: Option<i64>,
11424    /// 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.
11425    #[serde(default)]
11426    pub logo: Option<String>,
11427    /// 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.
11428    pub logo_mark_dark: bool,
11429    /// Team brand color as a hex string (provider-owned).
11430    #[serde(default)]
11431    pub color: Option<String>,
11432    /// Win-loss record as a display string (e.g. "12-4").
11433    #[serde(default)]
11434    pub record: Option<String>,
11435    /// Live or final score as a display string when the game is in play or settled.
11436    #[serde(default)]
11437    pub score: Option<String>,
11438    /// 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.
11439    #[serde(default, skip_serializing_if = "Option::is_none")]
11440    pub headshot: Option<String>,
11441    /// 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.
11442    #[serde(default, skip_serializing_if = "Option::is_none")]
11443    pub tour: Option<Tour>,
11444    /// 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.
11445    #[serde(default, skip_serializing_if = "Option::is_none")]
11446    pub sets: Option<Vec<ScoreCell>>,
11447    #[serde(default, skip_serializing_if = "Option::is_none")]
11448    pub format: Option<ScoreFormat>,
11449    /// 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.
11450    #[serde(default, skip_serializing_if = "Option::is_none")]
11451    pub sets_won: Option<i64>,
11452    /// 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.
11453    #[serde(default, skip_serializing_if = "Option::is_none")]
11454    pub headshot_revision: Option<i64>,
11455    /// 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.
11456    #[serde(default, skip_serializing_if = "Option::is_none")]
11457    pub ranking: Option<TennisRanking>,
11458    /// 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.
11459    pub logo_mark_light: bool,
11460    /// 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.
11461    pub logo_mark_measured: bool,
11462}
11463
11464/// A value this release does not know is kept in `Other`, so a new value never fails a response.
11465#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
11466#[non_exhaustive]
11467pub enum Platform {
11468    /// `polymarket`
11469    #[serde(rename = "polymarket")]
11470    Polymarket,
11471    /// `all`
11472    #[serde(rename = "all")]
11473    All,
11474    /// A value this release does not know, kept as sent.
11475    #[serde(untagged)]
11476    Other(String),
11477}
11478
11479impl Platform {
11480    /// The value as the API spells it.
11481    pub fn as_str(&self) -> &str {
11482        match self {
11483            Self::Polymarket => "polymarket",
11484            Self::All => "all",
11485            Self::Other(value) => value,
11486        }
11487    }
11488}
11489
11490impl From<&str> for Platform {
11491    fn from(value: &str) -> Self {
11492        match value {
11493            "polymarket" => Self::Polymarket,
11494            "all" => Self::All,
11495            other => Self::Other(other.to_owned()),
11496        }
11497    }
11498}
11499
11500impl std::fmt::Display for Platform {
11501    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11502        f.write_str(self.as_str())
11503    }
11504}
11505
11506impl AsRef<str> for Platform {
11507    fn as_ref(&self) -> &str {
11508        self.as_str()
11509    }
11510}
11511
11512#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11513#[non_exhaustive]
11514pub struct PlatformCapabilities {
11515    pub grade: PlatformCapabilityStatus,
11516    pub pnl: PlatformCapabilityStatus,
11517    pub strategy: PlatformCapabilityStatus,
11518    pub timeline: PlatformCapabilityStatus,
11519    /// 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).
11520    pub large_trades: PlatformCapabilityStatus,
11521    /// 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.
11522    pub whale_signal: PlatformCapabilityStatus,
11523    pub suspicious_trades: PlatformCapabilityStatus,
11524    /// 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.
11525    pub insider_radar: PlatformCapabilityStatus,
11526    pub market_snapshot: PlatformCapabilityStatus,
11527}
11528
11529/// 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.
11530pub type PlatformCapabilityStatus = String;
11531
11532#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11533#[non_exhaustive]
11534pub struct Platforms {
11535    pub platforms: PlatformsPlatforms,
11536}
11537
11538#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11539#[non_exhaustive]
11540pub struct PlatformsPlatforms {
11541    pub polymarket: PlatformCapabilities,
11542}
11543
11544/// 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.
11545#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11546#[non_exhaustive]
11547pub struct PnlCorrection {
11548    /// The correction method.
11549    pub basis: String,
11550    /// The correction in USD. Negative when Polymarket overstates the wallet.
11551    pub amount: f64,
11552    /// 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.
11553    #[serde(default, skip_serializing_if = "Option::is_none")]
11554    pub realized: Option<f64>,
11555    /// 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.
11556    #[serde(default, skip_serializing_if = "Option::is_none")]
11557    pub net_total: Option<f64>,
11558    /// The newest measurement among the measured markets.
11559    pub as_of: String,
11560    /// Neg-risk markets whose measurement amount sums.
11561    pub markets_measured: i64,
11562    /// 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.
11563    #[serde(default, skip_serializing_if = "Option::is_none")]
11564    pub markets_excluded: Option<i64>,
11565}
11566
11567#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11568#[non_exhaustive]
11569pub struct Position {
11570    /// Composite prefixed ID `pos_<wallet>:<condition_id>:<outcome_index>`.
11571    pub id: String,
11572    /// Provider discriminator. Polymarket only.
11573    pub platform: String,
11574    /// Lowercased proxy wallet address.
11575    pub wallet: String,
11576    /// Binary outcome side. Non-binary positions are not surfaced on V1.
11577    pub side: Direction,
11578    /// The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets).
11579    #[serde(default)]
11580    pub token_id: Option<String>,
11581    /// Live share count from the wallet_positions mirror.
11582    pub shares: f64,
11583    /// Volume-weighted entry price for this leg.
11584    #[serde(default, skip_serializing_if = "Option::is_none")]
11585    pub avg_price: Option<f64>,
11586    /// Current mark-to-market value in USD (always non-null on V1 — pre-reconcile rows are excluded).
11587    pub current_value_usd: f64,
11588    #[serde(default, skip_serializing_if = "Option::is_none")]
11589    pub initial_value_usd: Option<f64>,
11590    /// Unrealized P&L for the open position (Polymarket `cashPnl`).
11591    #[serde(default, skip_serializing_if = "Option::is_none")]
11592    pub cash_pnl: Option<f64>,
11593    /// Closed-leg P&L rolled up (Polymarket `realizedPnl`).
11594    #[serde(default, skip_serializing_if = "Option::is_none")]
11595    pub realized_pnl: Option<f64>,
11596    /// 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.
11597    #[serde(default, skip_serializing_if = "Option::is_none")]
11598    pub exact: Option<PositionExact>,
11599    /// Max updated_at across mirror legs for this pair.
11600    #[serde(default, skip_serializing_if = "Option::is_none")]
11601    pub last_reconciled_at: Option<String>,
11602    /// Backend-computed staleness bucket derived from last_reconciled_at.
11603    pub freshness: Freshness,
11604    pub trader: PositionTrader,
11605    pub market: PositionMarket,
11606}
11607
11608/// 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.
11609#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11610#[non_exhaustive]
11611pub struct PositionExact {
11612    pub shares: ExactDecimal,
11613    #[serde(default, skip_serializing_if = "Option::is_none")]
11614    pub cost_basis_usd: Option<ExactDecimal>,
11615    /// Exact derived price: `wallet_positions.cost_basis_usd / wallet_positions.shares`.
11616    #[serde(default, skip_serializing_if = "Option::is_none")]
11617    pub avg_price: Option<ExactDecimal>,
11618    pub current_value_usd: ExactDecimal,
11619    #[serde(default, skip_serializing_if = "Option::is_none")]
11620    pub initial_value_usd: Option<ExactDecimal>,
11621    #[serde(default, skip_serializing_if = "Option::is_none")]
11622    pub cash_pnl: Option<ExactDecimal>,
11623    #[serde(default, skip_serializing_if = "Option::is_none")]
11624    pub realized_pnl: Option<ExactDecimal>,
11625}
11626
11627#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11628#[non_exhaustive]
11629pub struct PositionMarket {
11630    /// Prefixed ID (`mkt_...`).
11631    pub id: String,
11632    pub condition_id: String,
11633    pub title: String,
11634    #[serde(default, skip_serializing_if = "Option::is_none")]
11635    pub slug: Option<String>,
11636    #[serde(default, skip_serializing_if = "Option::is_none")]
11637    pub event_slug: Option<String>,
11638    /// Provider-backed market_canonical category.
11639    #[serde(default, skip_serializing_if = "Option::is_none")]
11640    pub category: Option<String>,
11641    /// Provider-reported outcome label (e.g. team name for sports). Separate from `side` because provider labels can diverge from the binary Yes/No axis.
11642    #[serde(default, skip_serializing_if = "Option::is_none")]
11643    pub outcome_label: Option<String>,
11644    #[serde(default, skip_serializing_if = "Option::is_none")]
11645    pub end_date: Option<String>,
11646}
11647
11648#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11649#[non_exhaustive]
11650pub struct PositionTimelineEvent {
11651    /// Prefixed ID (pe_...).
11652    pub id: String,
11653    /// ISO 8601 timestamp of the on-chain fill.
11654    pub event_timestamp: String,
11655    /// The wallet's own side of this fill: buy or sell.
11656    pub action: Action,
11657    pub outcome_side: SuspiciousTradeFlaggedDataSide,
11658    /// The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. unsynced markets).
11659    #[serde(default)]
11660    pub token_id: Option<String>,
11661    /// Signed share delta (+ on buy, − on sell).
11662    pub amount_delta: f64,
11663    /// Fill price in USDC per share, in [0,1].
11664    pub price: f64,
11665    /// Positive USDC notional of the fill.
11666    pub usdc_notional: f64,
11667    /// Polygon transaction hash of the fill.
11668    pub tx_hash: String,
11669    /// 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.
11670    pub running_amount: f64,
11671    /// 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.
11672    pub running_avg_price: f64,
11673}
11674
11675#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11676#[non_exhaustive]
11677pub struct PositionTrader {
11678    /// Prefixed ID (`trd_...`).
11679    pub id: String,
11680    pub address: String,
11681    #[serde(default, skip_serializing_if = "Option::is_none")]
11682    pub username: Option<String>,
11683    #[serde(default, skip_serializing_if = "Option::is_none")]
11684    pub grade: Option<Grade>,
11685    /// 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.
11686    #[serde(default, skip_serializing_if = "Option::is_none")]
11687    pub win_rate: Option<f64>,
11688    /// 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.
11689    #[serde(default, skip_serializing_if = "Option::is_none")]
11690    pub pnl: Option<f64>,
11691    /// 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).
11692    #[serde(default, skip_serializing_if = "Option::is_none")]
11693    pub in_scope_realized_pnl: Option<f64>,
11694    /// 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.
11695    #[serde(default, skip_serializing_if = "Option::is_none")]
11696    pub markets: Option<i64>,
11697    /// 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.
11698    #[serde(default, skip_serializing_if = "Option::is_none")]
11699    pub wallet_age_days: Option<f64>,
11700    /// 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.
11701    pub is_new_wallet: bool,
11702}
11703
11704/// 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.
11705#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11706#[non_exhaustive]
11707pub struct PotdEntryAuthorization {
11708    pub version: i64,
11709    pub authorization_id: String,
11710    /// 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.
11711    pub policy_version: i64,
11712    pub condition_id: String,
11713    pub token_id: String,
11714    pub outcome_index: i64,
11715    /// Canonical sport bucket, not display_category.
11716    pub category: String,
11717    /// Exact provider parent event ID, or provider event ID when no parent exists.
11718    pub canonical_event_id: String,
11719    /// 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.
11720    pub max_entry_price: String,
11721    /// 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.
11722    pub reference_best_ask: String,
11723    pub reference_book_hash: String,
11724    pub reference_book_at: String,
11725    pub issued_at: String,
11726    /// Authorization expiry timestamp. Existing grants do not extend; an expired authorization cannot authorize a new automated entry.
11727    pub expires_at: String,
11728}
11729
11730#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11731#[non_exhaustive]
11732pub struct PrepareWebhookSecretResponse {
11733    pub object: String,
11734    pub data: WebhookEndpoint,
11735    pub meta: ResponseMeta,
11736}
11737
11738/// A value this release does not know is kept in `Other`, so a new value never fails a response.
11739#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
11740#[non_exhaustive]
11741pub enum PriceProvenance {
11742    /// `gamma_outcome_prices`
11743    #[serde(rename = "gamma_outcome_prices")]
11744    GammaOutcomePrices,
11745    /// `clob_display`
11746    #[serde(rename = "clob_display")]
11747    ClobDisplay,
11748    /// A value this release does not know, kept as sent.
11749    #[serde(untagged)]
11750    Other(String),
11751}
11752
11753impl PriceProvenance {
11754    /// The value as the API spells it.
11755    pub fn as_str(&self) -> &str {
11756        match self {
11757            Self::GammaOutcomePrices => "gamma_outcome_prices",
11758            Self::ClobDisplay => "clob_display",
11759            Self::Other(value) => value,
11760        }
11761    }
11762}
11763
11764impl From<&str> for PriceProvenance {
11765    fn from(value: &str) -> Self {
11766        match value {
11767            "gamma_outcome_prices" => Self::GammaOutcomePrices,
11768            "clob_display" => Self::ClobDisplay,
11769            other => Self::Other(other.to_owned()),
11770        }
11771    }
11772}
11773
11774impl std::fmt::Display for PriceProvenance {
11775    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11776        f.write_str(self.as_str())
11777    }
11778}
11779
11780impl AsRef<str> for PriceProvenance {
11781    fn as_ref(&self) -> &str {
11782        self.as_str()
11783    }
11784}
11785
11786/// 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.
11787#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11788#[non_exhaustive]
11789pub struct ProofPendingPickSlot {
11790    /// Deprecated compatibility daily release slot; use pick_id for identity and publication_order for scheduling.
11791    pub pick_rank: i64,
11792    /// The pick's stored release instant.
11793    pub release_at: String,
11794    /// The backed game's frozen kickoff instant; absent for a legacy row without one.
11795    #[serde(default, skip_serializing_if = "Option::is_none")]
11796    pub kickoff: Option<String>,
11797    /// 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.
11798    pub retry_at: String,
11799    /// Stable pick row identity as decimal text. Never use a quality rank as identity.
11800    pub pick_id: String,
11801    /// Compatibility release slot. No quality claim; historic scheduling order is retained.
11802    pub publication_order: i64,
11803    /// Viewer-independent free selection designation. New rows store it explicitly; historic null storage uses the original free slot.
11804    pub is_free_selection: bool,
11805    /// 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.
11806    #[serde(default)]
11807    pub supersedes_pick_id: Option<String>,
11808}
11809
11810/// A value this release does not know is kept in `Other`, so a new value never fails a response.
11811#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
11812#[non_exhaustive]
11813pub enum ProviderReadSource {
11814    /// `cached`
11815    #[serde(rename = "cached")]
11816    Cached,
11817    /// `live`
11818    #[serde(rename = "live")]
11819    Live,
11820    /// A value this release does not know, kept as sent.
11821    #[serde(untagged)]
11822    Other(String),
11823}
11824
11825impl ProviderReadSource {
11826    /// The value as the API spells it.
11827    pub fn as_str(&self) -> &str {
11828        match self {
11829            Self::Cached => "cached",
11830            Self::Live => "live",
11831            Self::Other(value) => value,
11832        }
11833    }
11834}
11835
11836impl From<&str> for ProviderReadSource {
11837    fn from(value: &str) -> Self {
11838        match value {
11839            "cached" => Self::Cached,
11840            "live" => Self::Live,
11841            other => Self::Other(other.to_owned()),
11842        }
11843    }
11844}
11845
11846impl std::fmt::Display for ProviderReadSource {
11847    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11848        f.write_str(self.as_str())
11849    }
11850}
11851
11852impl AsRef<str> for ProviderReadSource {
11853    fn as_ref(&self) -> &str {
11854        self.as_str()
11855    }
11856}
11857
11858/// A value this release does not know is kept in `Other`, so a new value never fails a response.
11859#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
11860#[non_exhaustive]
11861pub enum RankingSource {
11862    /// `live`
11863    #[serde(rename = "live")]
11864    Live,
11865    /// `db_only`
11866    #[serde(rename = "db_only")]
11867    DbOnly,
11868    /// A value this release does not know, kept as sent.
11869    #[serde(untagged)]
11870    Other(String),
11871}
11872
11873impl RankingSource {
11874    /// The value as the API spells it.
11875    pub fn as_str(&self) -> &str {
11876        match self {
11877            Self::Live => "live",
11878            Self::DbOnly => "db_only",
11879            Self::Other(value) => value,
11880        }
11881    }
11882}
11883
11884impl From<&str> for RankingSource {
11885    fn from(value: &str) -> Self {
11886        match value {
11887            "live" => Self::Live,
11888            "db_only" => Self::DbOnly,
11889            other => Self::Other(other.to_owned()),
11890        }
11891    }
11892}
11893
11894impl std::fmt::Display for RankingSource {
11895    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11896        f.write_str(self.as_str())
11897    }
11898}
11899
11900impl AsRef<str> for RankingSource {
11901    fn as_ref(&self) -> &str {
11902        self.as_str()
11903    }
11904}
11905
11906/// A value this release does not know is kept in `Other`, so a new value never fails a response.
11907#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
11908#[non_exhaustive]
11909pub enum Reason {
11910    /// `outcome_prices_missing`
11911    #[serde(rename = "outcome_prices_missing")]
11912    OutcomePricesMissing,
11913    /// `outcome_price_leg_missing`
11914    #[serde(rename = "outcome_price_leg_missing")]
11915    OutcomePriceLegMissing,
11916    /// `zero_price_sentinel`
11917    #[serde(rename = "zero_price_sentinel")]
11918    ZeroPriceSentinel,
11919    /// `display_price_pair_unavailable`
11920    #[serde(rename = "display_price_pair_unavailable")]
11921    DisplayPricePairUnavailable,
11922    /// `outcome_identity_unavailable`
11923    #[serde(rename = "outcome_identity_unavailable")]
11924    OutcomeIdentityUnavailable,
11925    /// `final_score_unavailable`
11926    #[serde(rename = "final_score_unavailable")]
11927    FinalScoreUnavailable,
11928    /// A value this release does not know, kept as sent.
11929    #[serde(untagged)]
11930    Other(String),
11931}
11932
11933impl Reason {
11934    /// The value as the API spells it.
11935    pub fn as_str(&self) -> &str {
11936        match self {
11937            Self::OutcomePricesMissing => "outcome_prices_missing",
11938            Self::OutcomePriceLegMissing => "outcome_price_leg_missing",
11939            Self::ZeroPriceSentinel => "zero_price_sentinel",
11940            Self::DisplayPricePairUnavailable => "display_price_pair_unavailable",
11941            Self::OutcomeIdentityUnavailable => "outcome_identity_unavailable",
11942            Self::FinalScoreUnavailable => "final_score_unavailable",
11943            Self::Other(value) => value,
11944        }
11945    }
11946}
11947
11948impl From<&str> for Reason {
11949    fn from(value: &str) -> Self {
11950        match value {
11951            "outcome_prices_missing" => Self::OutcomePricesMissing,
11952            "outcome_price_leg_missing" => Self::OutcomePriceLegMissing,
11953            "zero_price_sentinel" => Self::ZeroPriceSentinel,
11954            "display_price_pair_unavailable" => Self::DisplayPricePairUnavailable,
11955            "outcome_identity_unavailable" => Self::OutcomeIdentityUnavailable,
11956            "final_score_unavailable" => Self::FinalScoreUnavailable,
11957            other => Self::Other(other.to_owned()),
11958        }
11959    }
11960}
11961
11962impl std::fmt::Display for Reason {
11963    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11964        f.write_str(self.as_str())
11965    }
11966}
11967
11968impl AsRef<str> for Reason {
11969    fn as_ref(&self) -> &str {
11970        self.as_str()
11971    }
11972}
11973
11974#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11975#[non_exhaustive]
11976pub struct RedeliverWebhookDeliveryResponse {
11977    pub object: String,
11978    pub data: WebhookDelivery,
11979    pub meta: ResponseMeta,
11980}
11981
11982#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11983#[non_exhaustive]
11984pub struct RegisterAgentResponse {
11985    pub object: String,
11986    pub data: AgentRegistration,
11987    pub meta: ResponseMeta,
11988}
11989
11990#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11991#[non_exhaustive]
11992pub struct ReportPayload {
11993    /// 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).
11994    #[serde(default)]
11995    pub total_large_trades: Option<i64>,
11996    #[serde(default)]
11997    pub total_whale_trades: Option<i64>,
11998    /// 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).
11999    #[serde(default)]
12000    pub total_large_trade_volume: Option<f64>,
12001    #[serde(default)]
12002    pub total_whale_volume: Option<f64>,
12003    #[serde(default)]
12004    pub biggest_trade_size: Option<f64>,
12005    #[serde(default)]
12006    pub active_traders: Option<i64>,
12007    /// 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).
12008    #[serde(default)]
12009    pub top_large_trades: Option<Vec<ReportPayloadTopLargeTradesItem>>,
12010    #[serde(default)]
12011    pub top_whale_trades: Option<Vec<ReportPayloadTopWhaleTradesItem>>,
12012    #[serde(default)]
12013    pub categories: Option<Vec<ReportPayloadCategoriesItem>>,
12014    /// 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.
12015    #[serde(default)]
12016    pub grade_distribution: Option<Vec<ReportPayloadGradeDistributionItem>>,
12017    /// 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.
12018    pub market_scope: MarketScope,
12019}
12020
12021#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12022#[non_exhaustive]
12023pub struct ReportPayloadCategoriesItem {
12024    #[serde(default)]
12025    pub category: Option<String>,
12026    #[serde(default)]
12027    pub large_trade_count: Option<i64>,
12028    #[serde(default)]
12029    pub whale_trade_count: Option<i64>,
12030    #[serde(default)]
12031    pub category_volume: Option<f64>,
12032}
12033
12034#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12035#[non_exhaustive]
12036pub struct ReportPayloadGradeDistributionItem {
12037    #[serde(default)]
12038    pub grade: Option<Grade>,
12039    #[serde(default)]
12040    pub count: Option<i64>,
12041}
12042
12043#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12044#[non_exhaustive]
12045pub struct ReportPayloadTopLargeTradesItem {
12046    /// Provider outcome label for the traded side.
12047    #[serde(default)]
12048    pub outcome: Option<String>,
12049    /// Trade direction (BUY or SELL), not the outcome side.
12050    #[serde(default)]
12051    pub side: Option<String>,
12052    /// Market title.
12053    #[serde(default)]
12054    pub title: Option<String>,
12055    /// Trade size in USD.
12056    #[serde(default)]
12057    pub size: Option<f64>,
12058    /// Trade price in provider [0, 1] units.
12059    #[serde(default)]
12060    pub price: Option<f64>,
12061    /// The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the traded outcome; null when unavailable (e.g. unsynced markets).
12062    #[serde(default)]
12063    pub token_id: Option<String>,
12064    /// Whale trade id.
12065    #[serde(default)]
12066    pub id: Option<i64>,
12067    /// Trade timestamp (UTC).
12068    #[serde(default)]
12069    pub trade_time: Option<String>,
12070    /// Provider market category.
12071    #[serde(default)]
12072    pub market_category: Option<String>,
12073    /// Always polymarket, or null when the row carries no stored value.
12074    #[serde(default)]
12075    pub platform: Option<String>,
12076    /// Trader display name, when known.
12077    #[serde(default)]
12078    pub name: Option<String>,
12079    /// Trader pseudonym, when no display name is known.
12080    #[serde(default)]
12081    pub pseudonym: Option<String>,
12082    /// Trader grade (S-F) at snapshot time.
12083    #[serde(default)]
12084    pub trader_grade: Option<Grade>,
12085}
12086
12087#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12088#[non_exhaustive]
12089pub struct ReportPayloadTopWhaleTradesItem {
12090    /// Provider outcome label for the traded side.
12091    #[serde(default)]
12092    pub outcome: Option<String>,
12093    /// Trade direction (BUY or SELL), not the outcome side.
12094    #[serde(default)]
12095    pub side: Option<String>,
12096    /// Market title.
12097    #[serde(default)]
12098    pub title: Option<String>,
12099    /// Trade size in USD.
12100    #[serde(default)]
12101    pub size: Option<f64>,
12102    /// Trade price in provider [0, 1] units.
12103    #[serde(default)]
12104    pub price: Option<f64>,
12105    /// The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the traded outcome; null when unavailable (e.g. unsynced markets).
12106    #[serde(default)]
12107    pub token_id: Option<String>,
12108    /// Whale trade id.
12109    #[serde(default)]
12110    pub id: Option<i64>,
12111    /// Trade timestamp (UTC).
12112    #[serde(default)]
12113    pub trade_time: Option<String>,
12114    /// Provider market category.
12115    #[serde(default)]
12116    pub market_category: Option<String>,
12117    /// Always polymarket, or null when the row carries no stored value.
12118    #[serde(default)]
12119    pub platform: Option<String>,
12120    /// Trader display name, when known.
12121    #[serde(default)]
12122    pub name: Option<String>,
12123    /// Trader pseudonym, when no display name is known.
12124    #[serde(default)]
12125    pub pseudonym: Option<String>,
12126    /// Trader grade (S-F) at snapshot time.
12127    #[serde(default)]
12128    pub trader_grade: Option<Grade>,
12129}
12130
12131#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12132#[non_exhaustive]
12133pub struct ReportReconciliation {
12134    pub volume_kind: String,
12135    /// 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.
12136    pub whale_volume_source: String,
12137    pub notes: String,
12138}
12139
12140#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12141#[non_exhaustive]
12142pub struct ReportSnapshot {
12143    pub kind: Granularity,
12144    pub generated_at: String,
12145    pub source_range: ReportSourceRange,
12146    pub snapshot: SnapshotState,
12147    pub completeness: SnapshotCompleteness,
12148    pub reconciliation: ReportReconciliation,
12149    pub report: ReportPayload,
12150}
12151
12152#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12153#[non_exhaustive]
12154pub struct ReportSourceRange {
12155    pub start_date: String,
12156    pub end_date: String,
12157    pub timezone: String,
12158}
12159
12160/// A value this release does not know is kept in `Other`, so a new value never fails a response.
12161#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12162#[non_exhaustive]
12163pub enum RequiredTier {
12164    /// `account`
12165    #[serde(rename = "account")]
12166    Account,
12167    /// `insider`
12168    #[serde(rename = "insider")]
12169    Insider,
12170    /// `max`
12171    #[serde(rename = "max")]
12172    Max,
12173    /// A value this release does not know, kept as sent.
12174    #[serde(untagged)]
12175    Other(String),
12176}
12177
12178impl RequiredTier {
12179    /// The value as the API spells it.
12180    pub fn as_str(&self) -> &str {
12181        match self {
12182            Self::Account => "account",
12183            Self::Insider => "insider",
12184            Self::Max => "max",
12185            Self::Other(value) => value,
12186        }
12187    }
12188}
12189
12190impl From<&str> for RequiredTier {
12191    fn from(value: &str) -> Self {
12192        match value {
12193            "account" => Self::Account,
12194            "insider" => Self::Insider,
12195            "max" => Self::Max,
12196            other => Self::Other(other.to_owned()),
12197        }
12198    }
12199}
12200
12201impl std::fmt::Display for RequiredTier {
12202    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12203        f.write_str(self.as_str())
12204    }
12205}
12206
12207impl AsRef<str> for RequiredTier {
12208    fn as_ref(&self) -> &str {
12209        self.as_str()
12210    }
12211}
12212
12213/// A value this release does not know is kept in `Other`, so a new value never fails a response.
12214#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12215#[non_exhaustive]
12216pub enum Resolution {
12217    /// `1d`
12218    #[serde(rename = "1d")]
12219    V1d,
12220    /// `1w`
12221    #[serde(rename = "1w")]
12222    V1w,
12223    /// A value this release does not know, kept as sent.
12224    #[serde(untagged)]
12225    Other(String),
12226}
12227
12228impl Resolution {
12229    /// The value as the API spells it.
12230    pub fn as_str(&self) -> &str {
12231        match self {
12232            Self::V1d => "1d",
12233            Self::V1w => "1w",
12234            Self::Other(value) => value,
12235        }
12236    }
12237}
12238
12239impl From<&str> for Resolution {
12240    fn from(value: &str) -> Self {
12241        match value {
12242            "1d" => Self::V1d,
12243            "1w" => Self::V1w,
12244            other => Self::Other(other.to_owned()),
12245        }
12246    }
12247}
12248
12249impl std::fmt::Display for Resolution {
12250    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12251        f.write_str(self.as_str())
12252    }
12253}
12254
12255impl AsRef<str> for Resolution {
12256    fn as_ref(&self) -> &str {
12257        self.as_str()
12258    }
12259}
12260
12261#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12262#[non_exhaustive]
12263pub struct ResolutionReport {
12264    #[serde(default)]
12265    pub accuracy: Option<f64>,
12266    #[serde(default)]
12267    pub all_wallets_accuracy: Option<f64>,
12268    #[serde(default)]
12269    pub all_wallets_right: Option<i64>,
12270    #[serde(default)]
12271    pub all_wallets_wrong: Option<i64>,
12272    #[serde(default)]
12273    pub date: Option<String>,
12274    #[serde(default)]
12275    pub generated_at: Option<String>,
12276    #[serde(default)]
12277    pub grade_basis: Option<GradeBasis>,
12278    pub market_scope: MarketScope,
12279    #[serde(default, skip_serializing_if = "Option::is_none")]
12280    pub markets: Option<Vec<ResolutionReportMarketsItem>>,
12281    #[serde(default)]
12282    pub markets_without_smart_positions: Option<i64>,
12283    #[serde(default)]
12284    pub no_consensus: Option<i64>,
12285    #[serde(default)]
12286    pub positions_grade_unknown: Option<i64>,
12287    #[serde(default)]
12288    pub positions_without_side: Option<i64>,
12289    #[serde(default)]
12290    pub smart_money_right: Option<i64>,
12291    #[serde(default)]
12292    pub smart_money_wrong: Option<i64>,
12293    pub source_updates_pending: bool,
12294    #[serde(default)]
12295    pub time_basis_counts: Option<ResolutionReportTimeBasisCounts>,
12296    #[serde(default)]
12297    pub total_resolved: Option<i64>,
12298    #[serde(default)]
12299    pub total_smart_pnl: Option<f64>,
12300    #[serde(default)]
12301    pub with_smart_positions: Option<i64>,
12302}
12303
12304#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12305#[non_exhaustive]
12306pub struct ResolutionReportMarketsItem {
12307    #[serde(default)]
12308    pub all_wallets_right: Option<bool>,
12309    #[serde(default)]
12310    pub category: Option<String>,
12311    #[serde(default)]
12312    pub condition_id: Option<String>,
12313    #[serde(default)]
12314    pub confidence: Option<f64>,
12315    #[serde(default)]
12316    pub event_slug: Option<String>,
12317    pub out_of_product_scope: bool,
12318    #[serde(default)]
12319    pub outcome_no: Option<String>,
12320    #[serde(default)]
12321    pub outcome_yes: Option<String>,
12322    pub report_at: String,
12323    #[serde(default)]
12324    pub smart_consensus: Option<String>,
12325    #[serde(default)]
12326    pub smart_right: Option<bool>,
12327    #[serde(default)]
12328    pub smart_trader_count: Option<i64>,
12329    pub time_basis: TimeBasis,
12330    #[serde(default)]
12331    pub title: Option<String>,
12332    #[serde(default)]
12333    pub total_smart_pnl: Option<f64>,
12334    pub traders: Vec<ResolutionReportMarketsItemTradersItem>,
12335    #[serde(default)]
12336    pub weighted_no: Option<f64>,
12337    #[serde(default)]
12338    pub weighted_yes: Option<f64>,
12339    #[serde(default)]
12340    pub winning_outcome: Option<i64>,
12341}
12342
12343#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12344#[non_exhaustive]
12345pub struct ResolutionReportMarketsItemTradersItem {
12346    #[serde(default)]
12347    pub address: Option<String>,
12348    #[serde(default)]
12349    pub correct: Option<bool>,
12350    #[serde(default)]
12351    pub cost: Option<f64>,
12352    #[serde(default)]
12353    pub grade: Option<Grade>,
12354    #[serde(default)]
12355    pub last_traded_at: Option<String>,
12356    #[serde(default)]
12357    pub pnl: Option<f64>,
12358    #[serde(default)]
12359    pub side: Option<String>,
12360    #[serde(default)]
12361    pub username: Option<String>,
12362}
12363
12364#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12365#[non_exhaustive]
12366pub struct ResolutionReportTimeBasisCounts {
12367    pub observed_resolution: i64,
12368    pub polymarket_gamma_closed_time: i64,
12369}
12370
12371#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12372#[non_exhaustive]
12373pub struct ResponseMeta {
12374    /// 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.
12375    pub request_id: String,
12376    pub cached: bool,
12377    /// 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.
12378    #[serde(default, skip_serializing_if = "Option::is_none")]
12379    pub cache_age_s: Option<i64>,
12380    /// Advisory request weight (relative compute cost). 1 for simple reads; higher for heavier endpoints. Not a credit/price.
12381    pub cost: i64,
12382    /// 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.
12383    #[serde(default, skip_serializing_if = "Option::is_none")]
12384    pub ranking_generation: Option<i64>,
12385    /// 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.
12386    #[serde(default, skip_serializing_if = "Option::is_none")]
12387    pub ranking_as_of: Option<String>,
12388    /// Directional evidence provenance for Edge Hunter signals collections. The default board carries this provenance in data.directional_source and omits this optional meta field.
12389    #[serde(default, skip_serializing_if = "Option::is_none")]
12390    pub directional_source: Option<DirectionalSource>,
12391    /// 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.
12392    #[serde(default, skip_serializing_if = "Option::is_none")]
12393    pub ranking_source: Option<RankingSource>,
12394    /// Whole filtered snapshot category-evidence status before pagination. Operational live always remains partial source coverage.
12395    #[serde(default, skip_serializing_if = "Option::is_none")]
12396    pub category_skill_source: Option<CategorySkillSource>,
12397    #[serde(default, skip_serializing_if = "Option::is_none")]
12398    pub category_skill_model_version: Option<String>,
12399    #[serde(default, skip_serializing_if = "Option::is_none")]
12400    pub category_skill_taxonomy_version: Option<String>,
12401    #[serde(default, skip_serializing_if = "Option::is_none")]
12402    pub category_skill_platform: Option<String>,
12403    #[serde(default, skip_serializing_if = "Option::is_none")]
12404    pub category_skill_scope: Option<String>,
12405    #[serde(default, skip_serializing_if = "Option::is_none")]
12406    pub category_skill_source_coverage: Option<SourceCoverage>,
12407    #[serde(default, skip_serializing_if = "Option::is_none")]
12408    pub category_skill_observation_started_at: Option<String>,
12409    /// 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.
12410    #[serde(default, skip_serializing_if = "Option::is_none")]
12411    pub category_skill_model_operationally_degraded: Option<bool>,
12412    #[serde(default, skip_serializing_if = "Option::is_none")]
12413    pub category_skill_status_counts: Option<ResponseMetaCategorySkillStatusCounts>,
12414    /// SHA-256 of the funded signal membership/order/rank/cursor vector immediately before category-skill enrichment. Edge Hunter signals view only.
12415    #[serde(default, skip_serializing_if = "Option::is_none")]
12416    pub category_skill_base_payload_hash: Option<String>,
12417    /// 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.
12418    #[serde(default, skip_serializing_if = "Option::is_none")]
12419    pub category_skill_enriched_base_payload_hash: Option<String>,
12420}
12421
12422#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12423#[non_exhaustive]
12424pub struct ResponseMetaCategorySkillStatusCounts {
12425    pub live: i64,
12426    pub insufficient: i64,
12427    pub stale: i64,
12428    pub unknown: i64,
12429    pub degraded: i64,
12430}
12431
12432#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12433#[non_exhaustive]
12434pub struct RetireWebhookSecretResponse {
12435    pub object: String,
12436    pub data: WebhookEndpoint,
12437    pub meta: ResponseMeta,
12438}
12439
12440/// A value this release does not know is kept in `Other`, so a new value never fails a response.
12441#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12442#[non_exhaustive]
12443pub enum RetryScheduleReason {
12444    /// `receiver_retry_after`
12445    #[serde(rename = "receiver_retry_after")]
12446    ReceiverRetryAfter,
12447    /// `transient_failure`
12448    #[serde(rename = "transient_failure")]
12449    TransientFailure,
12450    /// `permanent_or_auth_failure`
12451    #[serde(rename = "permanent_or_auth_failure")]
12452    PermanentOrAuthFailure,
12453    /// `manual_redelivery`
12454    #[serde(rename = "manual_redelivery")]
12455    ManualRedelivery,
12456    /// `configuration_changed`
12457    #[serde(rename = "configuration_changed")]
12458    ConfigurationChanged,
12459    /// A value this release does not know, kept as sent.
12460    #[serde(untagged)]
12461    Other(String),
12462}
12463
12464impl RetryScheduleReason {
12465    /// The value as the API spells it.
12466    pub fn as_str(&self) -> &str {
12467        match self {
12468            Self::ReceiverRetryAfter => "receiver_retry_after",
12469            Self::TransientFailure => "transient_failure",
12470            Self::PermanentOrAuthFailure => "permanent_or_auth_failure",
12471            Self::ManualRedelivery => "manual_redelivery",
12472            Self::ConfigurationChanged => "configuration_changed",
12473            Self::Other(value) => value,
12474        }
12475    }
12476}
12477
12478impl From<&str> for RetryScheduleReason {
12479    fn from(value: &str) -> Self {
12480        match value {
12481            "receiver_retry_after" => Self::ReceiverRetryAfter,
12482            "transient_failure" => Self::TransientFailure,
12483            "permanent_or_auth_failure" => Self::PermanentOrAuthFailure,
12484            "manual_redelivery" => Self::ManualRedelivery,
12485            "configuration_changed" => Self::ConfigurationChanged,
12486            other => Self::Other(other.to_owned()),
12487        }
12488    }
12489}
12490
12491impl std::fmt::Display for RetryScheduleReason {
12492    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12493        f.write_str(self.as_str())
12494    }
12495}
12496
12497impl AsRef<str> for RetryScheduleReason {
12498    fn as_ref(&self) -> &str {
12499        self.as_str()
12500    }
12501}
12502
12503#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12504#[non_exhaustive]
12505pub struct RotateWebhookSecretResponse {
12506    pub object: String,
12507    pub data: WebhookEndpoint,
12508    pub meta: ResponseMeta,
12509}
12510
12511/// 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.
12512#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12513#[non_exhaustive]
12514pub struct ScheduledPickSlot {
12515    /// Deprecated compatibility daily release slot; use pick_id for identity and publication_order for scheduling.
12516    pub pick_rank: i64,
12517    /// 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.
12518    pub release_at: String,
12519    /// The backed game's current kickoff instant.
12520    pub kickoff: String,
12521    /// Stable pick row identity as decimal text. Never use a quality rank as identity.
12522    pub pick_id: String,
12523    /// Compatibility release slot. No quality claim; historic scheduling order is retained.
12524    pub publication_order: i64,
12525    /// Viewer-independent free selection designation. New rows store it explicitly; historic null storage uses the original free slot.
12526    pub is_free_selection: bool,
12527    /// 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.
12528    #[serde(default)]
12529    pub supersedes_pick_id: Option<String>,
12530}
12531
12532/// A value this release does not know is kept in `Other`, so a new value never fails a response.
12533#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12534#[non_exhaustive]
12535pub enum SchemaVersion {
12536    /// `trader-export-json-v1`
12537    #[serde(rename = "trader-export-json-v1")]
12538    TraderExportJsonV1,
12539    /// `trader-export-ndjson-v1`
12540    #[serde(rename = "trader-export-ndjson-v1")]
12541    TraderExportNdjsonV1,
12542    /// `trader-export-csv-v1`
12543    #[serde(rename = "trader-export-csv-v1")]
12544    TraderExportCsvV1,
12545    /// A value this release does not know, kept as sent.
12546    #[serde(untagged)]
12547    Other(String),
12548}
12549
12550impl SchemaVersion {
12551    /// The value as the API spells it.
12552    pub fn as_str(&self) -> &str {
12553        match self {
12554            Self::TraderExportJsonV1 => "trader-export-json-v1",
12555            Self::TraderExportNdjsonV1 => "trader-export-ndjson-v1",
12556            Self::TraderExportCsvV1 => "trader-export-csv-v1",
12557            Self::Other(value) => value,
12558        }
12559    }
12560}
12561
12562impl From<&str> for SchemaVersion {
12563    fn from(value: &str) -> Self {
12564        match value {
12565            "trader-export-json-v1" => Self::TraderExportJsonV1,
12566            "trader-export-ndjson-v1" => Self::TraderExportNdjsonV1,
12567            "trader-export-csv-v1" => Self::TraderExportCsvV1,
12568            other => Self::Other(other.to_owned()),
12569        }
12570    }
12571}
12572
12573impl std::fmt::Display for SchemaVersion {
12574    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12575        f.write_str(self.as_str())
12576    }
12577}
12578
12579impl AsRef<str> for SchemaVersion {
12580    fn as_ref(&self) -> &str {
12581        self.as_str()
12582    }
12583}
12584
12585/// One side's score in a single set. The verbatim provider text stays on the team's `score` string; this is the parsed form.
12586#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12587#[non_exhaustive]
12588pub struct ScoreCell {
12589    /// Games won in this set.
12590    pub games: i64,
12591    /// Tiebreak points won in this set. Omitted when the set had no tiebreak; absence and zero are different.
12592    #[serde(default, skip_serializing_if = "Option::is_none")]
12593    pub tiebreak: Option<i64>,
12594}
12595
12596/// 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.
12597///
12598/// A value this release does not know is kept in `Other`, so a new value never fails a response.
12599#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12600#[non_exhaustive]
12601pub enum ScoreFormat {
12602    /// `two_side`
12603    #[serde(rename = "two_side")]
12604    TwoSide,
12605    /// `multi_set`
12606    #[serde(rename = "multi_set")]
12607    MultiSet,
12608    /// `esports_series`
12609    #[serde(rename = "esports_series")]
12610    EsportsSeries,
12611    /// A value this release does not know, kept as sent.
12612    #[serde(untagged)]
12613    Other(String),
12614}
12615
12616impl ScoreFormat {
12617    /// The value as the API spells it.
12618    pub fn as_str(&self) -> &str {
12619        match self {
12620            Self::TwoSide => "two_side",
12621            Self::MultiSet => "multi_set",
12622            Self::EsportsSeries => "esports_series",
12623            Self::Other(value) => value,
12624        }
12625    }
12626}
12627
12628impl From<&str> for ScoreFormat {
12629    fn from(value: &str) -> Self {
12630        match value {
12631            "two_side" => Self::TwoSide,
12632            "multi_set" => Self::MultiSet,
12633            "esports_series" => Self::EsportsSeries,
12634            other => Self::Other(other.to_owned()),
12635        }
12636    }
12637}
12638
12639impl std::fmt::Display for ScoreFormat {
12640    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12641        f.write_str(self.as_str())
12642    }
12643}
12644
12645impl AsRef<str> for ScoreFormat {
12646    fn as_ref(&self) -> &str {
12647        self.as_str()
12648    }
12649}
12650
12651#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12652#[non_exhaustive]
12653pub struct SearchContentResponse {
12654    pub object: String,
12655    pub data: Vec<ContentSearchResult>,
12656    pub has_more: bool,
12657    /// Omitted because content search is a bounded one-page result.
12658    #[serde(default, skip_serializing_if = "Option::is_none")]
12659    pub next_cursor: Option<String>,
12660    /// Absent because content search is a bounded relevance result and does not run a count query.
12661    #[serde(default, skip_serializing_if = "Option::is_none")]
12662    pub total: Option<i64>,
12663    pub meta: ResponseMeta,
12664}
12665
12666#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12667#[non_exhaustive]
12668pub struct SearchMarketsResponse {
12669    pub object: String,
12670    pub data: Vec<MarketSearchResult>,
12671    pub has_more: bool,
12672    #[serde(default, skip_serializing_if = "Option::is_none")]
12673    pub next_cursor: Option<String>,
12674    /// Total matching rows when the read model exposes a count; the key is absent when it does not.
12675    #[serde(default, skip_serializing_if = "Option::is_none")]
12676    pub total: Option<i64>,
12677    pub meta: ResponseMeta,
12678}
12679
12680/// A value this release does not know is kept in `Other`, so a new value never fails a response.
12681#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12682#[non_exhaustive]
12683pub enum SearchMarketsStatus {
12684    /// `active`
12685    #[serde(rename = "active")]
12686    Active,
12687    /// `closed`
12688    #[serde(rename = "closed")]
12689    Closed,
12690    /// `all`
12691    #[serde(rename = "all")]
12692    All,
12693    /// A value this release does not know, kept as sent.
12694    #[serde(untagged)]
12695    Other(String),
12696}
12697
12698impl SearchMarketsStatus {
12699    /// The value as the API spells it.
12700    pub fn as_str(&self) -> &str {
12701        match self {
12702            Self::Active => "active",
12703            Self::Closed => "closed",
12704            Self::All => "all",
12705            Self::Other(value) => value,
12706        }
12707    }
12708}
12709
12710impl From<&str> for SearchMarketsStatus {
12711    fn from(value: &str) -> Self {
12712        match value {
12713            "active" => Self::Active,
12714            "closed" => Self::Closed,
12715            "all" => Self::All,
12716            other => Self::Other(other.to_owned()),
12717        }
12718    }
12719}
12720
12721impl std::fmt::Display for SearchMarketsStatus {
12722    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12723        f.write_str(self.as_str())
12724    }
12725}
12726
12727impl AsRef<str> for SearchMarketsStatus {
12728    fn as_ref(&self) -> &str {
12729        self.as_str()
12730    }
12731}
12732
12733/// A value this release does not know is kept in `Other`, so a new value never fails a response.
12734#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12735#[non_exhaustive]
12736pub enum Sections {
12737    /// `entries`
12738    #[serde(rename = "entries")]
12739    Entries,
12740    /// `stats`
12741    #[serde(rename = "stats")]
12742    Stats,
12743    /// `monthly`
12744    #[serde(rename = "monthly")]
12745    Monthly,
12746    /// `year_totals`
12747    #[serde(rename = "year_totals")]
12748    YearTotals,
12749    /// `drawdown`
12750    #[serde(rename = "drawdown")]
12751    Drawdown,
12752    /// A value this release does not know, kept as sent.
12753    #[serde(untagged)]
12754    Other(String),
12755}
12756
12757impl Sections {
12758    /// The value as the API spells it.
12759    pub fn as_str(&self) -> &str {
12760        match self {
12761            Self::Entries => "entries",
12762            Self::Stats => "stats",
12763            Self::Monthly => "monthly",
12764            Self::YearTotals => "year_totals",
12765            Self::Drawdown => "drawdown",
12766            Self::Other(value) => value,
12767        }
12768    }
12769}
12770
12771impl From<&str> for Sections {
12772    fn from(value: &str) -> Self {
12773        match value {
12774            "entries" => Self::Entries,
12775            "stats" => Self::Stats,
12776            "monthly" => Self::Monthly,
12777            "year_totals" => Self::YearTotals,
12778            "drawdown" => Self::Drawdown,
12779            other => Self::Other(other.to_owned()),
12780        }
12781    }
12782}
12783
12784impl std::fmt::Display for Sections {
12785    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12786        f.write_str(self.as_str())
12787    }
12788}
12789
12790impl AsRef<str> for Sections {
12791    fn as_ref(&self) -> &str {
12792        self.as_str()
12793    }
12794}
12795
12796/// A value this release does not know is kept in `Other`, so a new value never fails a response.
12797#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12798#[non_exhaustive]
12799pub enum ServingSide {
12800    /// `first`
12801    #[serde(rename = "first")]
12802    First,
12803    /// `second`
12804    #[serde(rename = "second")]
12805    Second,
12806    /// A value this release does not know, kept as sent.
12807    #[serde(untagged)]
12808    Other(String),
12809}
12810
12811impl ServingSide {
12812    /// The value as the API spells it.
12813    pub fn as_str(&self) -> &str {
12814        match self {
12815            Self::First => "first",
12816            Self::Second => "second",
12817            Self::Other(value) => value,
12818        }
12819    }
12820}
12821
12822impl From<&str> for ServingSide {
12823    fn from(value: &str) -> Self {
12824        match value {
12825            "first" => Self::First,
12826            "second" => Self::Second,
12827            other => Self::Other(other.to_owned()),
12828        }
12829    }
12830}
12831
12832impl std::fmt::Display for ServingSide {
12833    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12834        f.write_str(self.as_str())
12835    }
12836}
12837
12838impl AsRef<str> for ServingSide {
12839    fn as_ref(&self) -> &str {
12840        self.as_str()
12841    }
12842}
12843
12844/// A value this release does not know is kept in `Other`, so a new value never fails a response.
12845#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12846#[non_exhaustive]
12847pub enum Severity {
12848    /// `flag`
12849    #[serde(rename = "flag")]
12850    Flag,
12851    /// `watch`
12852    #[serde(rename = "watch")]
12853    Watch,
12854    /// A value this release does not know, kept as sent.
12855    #[serde(untagged)]
12856    Other(String),
12857}
12858
12859impl Severity {
12860    /// The value as the API spells it.
12861    pub fn as_str(&self) -> &str {
12862        match self {
12863            Self::Flag => "flag",
12864            Self::Watch => "watch",
12865            Self::Other(value) => value,
12866        }
12867    }
12868}
12869
12870impl From<&str> for Severity {
12871    fn from(value: &str) -> Self {
12872        match value {
12873            "flag" => Self::Flag,
12874            "watch" => Self::Watch,
12875            other => Self::Other(other.to_owned()),
12876        }
12877    }
12878}
12879
12880impl std::fmt::Display for Severity {
12881    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12882        f.write_str(self.as_str())
12883    }
12884}
12885
12886impl AsRef<str> for Severity {
12887    fn as_ref(&self) -> &str {
12888        self.as_str()
12889    }
12890}
12891
12892/// `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).
12893#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12894#[non_exhaustive]
12895pub struct SharpMoneyFlowDetectedData {
12896    /// Polymarket condition id of the market.
12897    pub condition_id: String,
12898    /// Signed ranked-trader net flow in USD over `window`: positive is net into YES, negative net into NO.
12899    pub net_flow_usd: f64,
12900    /// Absolute value of `net_flow_usd`, the magnitude compared with the threshold.
12901    pub abs_net_flow_usd: f64,
12902    /// `yes` when `net_flow_usd` is 0 or more, else `no`.
12903    pub dominant_side: SuspiciousTradeFlaggedDataSide,
12904    /// Minimum trader grade included in the flow.
12905    pub grade_floor: Grade,
12906    /// Ranked-trader large fills that make up the flow.
12907    pub whale_trade_count: i64,
12908    /// Window the flow was aggregated over, for example `24h`.
12909    pub window: String,
12910}
12911
12912/// A value this release does not know is kept in `Other`, so a new value never fails a response.
12913#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12914#[non_exhaustive]
12915pub enum Side {
12916    /// `BUY`
12917    #[serde(rename = "BUY")]
12918    Buy,
12919    /// `SELL`
12920    #[serde(rename = "SELL")]
12921    Sell,
12922    /// A value this release does not know, kept as sent.
12923    #[serde(untagged)]
12924    Other(String),
12925}
12926
12927impl Side {
12928    /// The value as the API spells it.
12929    pub fn as_str(&self) -> &str {
12930        match self {
12931            Self::Buy => "BUY",
12932            Self::Sell => "SELL",
12933            Self::Other(value) => value,
12934        }
12935    }
12936}
12937
12938impl From<&str> for Side {
12939    fn from(value: &str) -> Self {
12940        match value {
12941            "BUY" => Self::Buy,
12942            "SELL" => Self::Sell,
12943            other => Self::Other(other.to_owned()),
12944        }
12945    }
12946}
12947
12948impl std::fmt::Display for Side {
12949    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12950        f.write_str(self.as_str())
12951    }
12952}
12953
12954impl AsRef<str> for Side {
12955    fn as_ref(&self) -> &str {
12956        self.as_str()
12957    }
12958}
12959
12960#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12961#[non_exhaustive]
12962pub struct SmartMoneyFlowMarket {
12963    pub market: SmartMoneyFlowMarketMarket,
12964    /// Sharp-money flow aggregate for the market (canonical; smart_money is a deprecated byte-identical alias).
12965    pub sharp_money: SmartMoneyFlowMarketSharpMoney,
12966    /// Deprecated alias of sharp_money; byte-identical. Sunset 2027-02-01 (#29352): removed from V1 on that date; read sharp_money.
12967    pub smart_money: SmartMoneyFlowMarketSmartMoney,
12968    pub timeframe: String,
12969}
12970
12971#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12972#[non_exhaustive]
12973pub struct SmartMoneyFlowMarketMarket {
12974    pub id: String,
12975    pub condition_id: String,
12976    #[serde(default)]
12977    pub title: Option<String>,
12978    #[serde(default)]
12979    pub slug: Option<String>,
12980    #[serde(default)]
12981    pub category: Option<String>,
12982    /// Provider platform. Always polymarket, or null when the row carries no stored value.
12983    #[serde(default)]
12984    pub platform: Option<String>,
12985}
12986
12987/// Sharp-money flow aggregate for the market (canonical; smart_money is a deprecated byte-identical alias).
12988#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12989#[non_exhaustive]
12990pub struct SmartMoneyFlowMarketSharpMoney {
12991    pub net_flow_usd: f64,
12992    pub direction: Direction,
12993    /// The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets).
12994    #[serde(default)]
12995    pub token_id: Option<String>,
12996    /// 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).
12997    pub large_trade_count: i64,
12998    /// 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.
12999    pub whale_trade_count: i64,
13000    pub buy_volume_usd: f64,
13001    pub sell_volume_usd: f64,
13002}
13003
13004/// Deprecated alias of sharp_money; byte-identical. Sunset 2027-02-01 (#29352): removed from V1 on that date; read sharp_money.
13005#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13006#[non_exhaustive]
13007pub struct SmartMoneyFlowMarketSmartMoney {
13008    pub net_flow_usd: f64,
13009    pub direction: Direction,
13010    /// The Polymarket CLOB token id (ERC1155 asset id, decimal string) for the net-flow direction outcome; null when unavailable (e.g. unsynced markets).
13011    #[serde(default)]
13012    pub token_id: Option<String>,
13013    /// 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).
13014    pub large_trade_count: i64,
13015    /// 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.
13016    pub whale_trade_count: i64,
13017    pub buy_volume_usd: f64,
13018    pub sell_volume_usd: f64,
13019}
13020
13021#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13022#[non_exhaustive]
13023pub struct SnapshotCompleteness {
13024    /// 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.
13025    pub status: SnapshotCompletenessStatus,
13026    pub reason: String,
13027    pub expected_days: i64,
13028    /// 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).
13029    pub covered_days_with_large_trade_activity: i64,
13030    /// 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.
13031    pub covered_days_with_whale_activity: i64,
13032}
13033
13034/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13035#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13036#[non_exhaustive]
13037pub enum SnapshotCompletenessStatus {
13038    /// `complete`
13039    #[serde(rename = "complete")]
13040    Complete,
13041    /// `partial`
13042    #[serde(rename = "partial")]
13043    Partial,
13044    /// `empty`
13045    #[serde(rename = "empty")]
13046    Empty,
13047    /// A value this release does not know, kept as sent.
13048    #[serde(untagged)]
13049    Other(String),
13050}
13051
13052impl SnapshotCompletenessStatus {
13053    /// The value as the API spells it.
13054    pub fn as_str(&self) -> &str {
13055        match self {
13056            Self::Complete => "complete",
13057            Self::Partial => "partial",
13058            Self::Empty => "empty",
13059            Self::Other(value) => value,
13060        }
13061    }
13062}
13063
13064impl From<&str> for SnapshotCompletenessStatus {
13065    fn from(value: &str) -> Self {
13066        match value {
13067            "complete" => Self::Complete,
13068            "partial" => Self::Partial,
13069            "empty" => Self::Empty,
13070            other => Self::Other(other.to_owned()),
13071        }
13072    }
13073}
13074
13075impl std::fmt::Display for SnapshotCompletenessStatus {
13076    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13077        f.write_str(self.as_str())
13078    }
13079}
13080
13081impl AsRef<str> for SnapshotCompletenessStatus {
13082    fn as_ref(&self) -> &str {
13083        self.as_str()
13084    }
13085}
13086
13087#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13088#[non_exhaustive]
13089pub struct SnapshotState {
13090    /// Immutable content version for a durable report identity; 0 for an ephemeral explicit weekly from/to range.
13091    pub version: i64,
13092    /// 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.
13093    pub storage: Storage,
13094    /// 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).
13095    pub status: SnapshotStateStatus,
13096    pub generated_at: String,
13097    /// For a rolling body, the UTC date on which a final body can first be built (the date of final_after); null once final.
13098    #[serde(default)]
13099    pub mutable_until: Option<String>,
13100    /// Whether the source range has ended on the UTC calendar. Closing is not finality: a closed range is rolling until final_after.
13101    pub period_closed: bool,
13102    /// 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).
13103    pub final_after: String,
13104    /// When this body's source read started, the clock finality is judged on. null for a body stored before that clock was recorded.
13105    #[serde(default)]
13106    pub source_read_started_at: Option<String>,
13107}
13108
13109/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13110#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13111#[non_exhaustive]
13112pub enum SnapshotStateStatus {
13113    /// `final`
13114    #[serde(rename = "final")]
13115    Final,
13116    /// `rolling`
13117    #[serde(rename = "rolling")]
13118    Rolling,
13119    /// A value this release does not know, kept as sent.
13120    #[serde(untagged)]
13121    Other(String),
13122}
13123
13124impl SnapshotStateStatus {
13125    /// The value as the API spells it.
13126    pub fn as_str(&self) -> &str {
13127        match self {
13128            Self::Final => "final",
13129            Self::Rolling => "rolling",
13130            Self::Other(value) => value,
13131        }
13132    }
13133}
13134
13135impl From<&str> for SnapshotStateStatus {
13136    fn from(value: &str) -> Self {
13137        match value {
13138            "final" => Self::Final,
13139            "rolling" => Self::Rolling,
13140            other => Self::Other(other.to_owned()),
13141        }
13142    }
13143}
13144
13145impl std::fmt::Display for SnapshotStateStatus {
13146    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13147        f.write_str(self.as_str())
13148    }
13149}
13150
13151impl AsRef<str> for SnapshotStateStatus {
13152    fn as_ref(&self) -> &str {
13153        self.as_str()
13154    }
13155}
13156
13157/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13158#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13159#[non_exhaustive]
13160pub enum Sort {
13161    /// `recent`
13162    #[serde(rename = "recent")]
13163    Recent,
13164    /// `market_volume_share`
13165    #[serde(rename = "market_volume_share")]
13166    MarketVolumeShare,
13167    /// A value this release does not know, kept as sent.
13168    #[serde(untagged)]
13169    Other(String),
13170}
13171
13172impl Sort {
13173    /// The value as the API spells it.
13174    pub fn as_str(&self) -> &str {
13175        match self {
13176            Self::Recent => "recent",
13177            Self::MarketVolumeShare => "market_volume_share",
13178            Self::Other(value) => value,
13179        }
13180    }
13181}
13182
13183impl From<&str> for Sort {
13184    fn from(value: &str) -> Self {
13185        match value {
13186            "recent" => Self::Recent,
13187            "market_volume_share" => Self::MarketVolumeShare,
13188            other => Self::Other(other.to_owned()),
13189        }
13190    }
13191}
13192
13193impl std::fmt::Display for Sort {
13194    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13195        f.write_str(self.as_str())
13196    }
13197}
13198
13199impl AsRef<str> for Sort {
13200    fn as_ref(&self) -> &str {
13201        self.as_str()
13202    }
13203}
13204
13205/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13206#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13207#[non_exhaustive]
13208pub enum Source {
13209    /// `polymarket_data`
13210    #[serde(rename = "polymarket_data")]
13211    PolymarketData,
13212    /// `gamma`
13213    #[serde(rename = "gamma")]
13214    Gamma,
13215    /// A value this release does not know, kept as sent.
13216    #[serde(untagged)]
13217    Other(String),
13218}
13219
13220impl Source {
13221    /// The value as the API spells it.
13222    pub fn as_str(&self) -> &str {
13223        match self {
13224            Self::PolymarketData => "polymarket_data",
13225            Self::Gamma => "gamma",
13226            Self::Other(value) => value,
13227        }
13228    }
13229}
13230
13231impl From<&str> for Source {
13232    fn from(value: &str) -> Self {
13233        match value {
13234            "polymarket_data" => Self::PolymarketData,
13235            "gamma" => Self::Gamma,
13236            other => Self::Other(other.to_owned()),
13237        }
13238    }
13239}
13240
13241impl std::fmt::Display for Source {
13242    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13243        f.write_str(self.as_str())
13244    }
13245}
13246
13247impl AsRef<str> for Source {
13248    fn as_ref(&self) -> &str {
13249        self.as_str()
13250    }
13251}
13252
13253/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13254#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13255#[non_exhaustive]
13256pub enum SourceAvailability {
13257    /// `available`
13258    #[serde(rename = "available")]
13259    Available,
13260    /// `unavailable`
13261    #[serde(rename = "unavailable")]
13262    Unavailable,
13263    /// `not_applicable`
13264    #[serde(rename = "not_applicable")]
13265    NotApplicable,
13266    /// A value this release does not know, kept as sent.
13267    #[serde(untagged)]
13268    Other(String),
13269}
13270
13271impl SourceAvailability {
13272    /// The value as the API spells it.
13273    pub fn as_str(&self) -> &str {
13274        match self {
13275            Self::Available => "available",
13276            Self::Unavailable => "unavailable",
13277            Self::NotApplicable => "not_applicable",
13278            Self::Other(value) => value,
13279        }
13280    }
13281}
13282
13283impl From<&str> for SourceAvailability {
13284    fn from(value: &str) -> Self {
13285        match value {
13286            "available" => Self::Available,
13287            "unavailable" => Self::Unavailable,
13288            "not_applicable" => Self::NotApplicable,
13289            other => Self::Other(other.to_owned()),
13290        }
13291    }
13292}
13293
13294impl std::fmt::Display for SourceAvailability {
13295    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13296        f.write_str(self.as_str())
13297    }
13298}
13299
13300impl AsRef<str> for SourceAvailability {
13301    fn as_ref(&self) -> &str {
13302        self.as_str()
13303    }
13304}
13305
13306/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13307#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13308#[non_exhaustive]
13309pub enum SourceCoverage {
13310    /// `partial_whale_threshold_fills`
13311    #[serde(rename = "partial_whale_threshold_fills")]
13312    PartialWhaleThresholdFills,
13313    /// `graded_wallet_fills`
13314    #[serde(rename = "graded_wallet_fills")]
13315    GradedWalletFills,
13316    /// A value this release does not know, kept as sent.
13317    #[serde(untagged)]
13318    Other(String),
13319}
13320
13321impl SourceCoverage {
13322    /// The value as the API spells it.
13323    pub fn as_str(&self) -> &str {
13324        match self {
13325            Self::PartialWhaleThresholdFills => "partial_whale_threshold_fills",
13326            Self::GradedWalletFills => "graded_wallet_fills",
13327            Self::Other(value) => value,
13328        }
13329    }
13330}
13331
13332impl From<&str> for SourceCoverage {
13333    fn from(value: &str) -> Self {
13334        match value {
13335            "partial_whale_threshold_fills" => Self::PartialWhaleThresholdFills,
13336            "graded_wallet_fills" => Self::GradedWalletFills,
13337            other => Self::Other(other.to_owned()),
13338        }
13339    }
13340}
13341
13342impl std::fmt::Display for SourceCoverage {
13343    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13344        f.write_str(self.as_str())
13345    }
13346}
13347
13348impl AsRef<str> for SourceCoverage {
13349    fn as_ref(&self) -> &str {
13350        self.as_str()
13351    }
13352}
13353
13354/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13355#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13356#[non_exhaustive]
13357pub enum SourceFreshness {
13358    /// `fresh`
13359    #[serde(rename = "fresh")]
13360    Fresh,
13361    /// `stale`
13362    #[serde(rename = "stale")]
13363    Stale,
13364    /// `unknown`
13365    #[serde(rename = "unknown")]
13366    Unknown,
13367    /// `not_applicable`
13368    #[serde(rename = "not_applicable")]
13369    NotApplicable,
13370    /// A value this release does not know, kept as sent.
13371    #[serde(untagged)]
13372    Other(String),
13373}
13374
13375impl SourceFreshness {
13376    /// The value as the API spells it.
13377    pub fn as_str(&self) -> &str {
13378        match self {
13379            Self::Fresh => "fresh",
13380            Self::Stale => "stale",
13381            Self::Unknown => "unknown",
13382            Self::NotApplicable => "not_applicable",
13383            Self::Other(value) => value,
13384        }
13385    }
13386}
13387
13388impl From<&str> for SourceFreshness {
13389    fn from(value: &str) -> Self {
13390        match value {
13391            "fresh" => Self::Fresh,
13392            "stale" => Self::Stale,
13393            "unknown" => Self::Unknown,
13394            "not_applicable" => Self::NotApplicable,
13395            other => Self::Other(other.to_owned()),
13396        }
13397    }
13398}
13399
13400impl std::fmt::Display for SourceFreshness {
13401    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13402        f.write_str(self.as_str())
13403    }
13404}
13405
13406impl AsRef<str> for SourceFreshness {
13407    fn as_ref(&self) -> &str {
13408        self.as_str()
13409    }
13410}
13411
13412/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13413#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13414#[non_exhaustive]
13415pub enum SourceStatus {
13416    /// `ok`
13417    #[serde(rename = "ok")]
13418    Ok,
13419    /// `unavailable`
13420    #[serde(rename = "unavailable")]
13421    Unavailable,
13422    /// A value this release does not know, kept as sent.
13423    #[serde(untagged)]
13424    Other(String),
13425}
13426
13427impl SourceStatus {
13428    /// The value as the API spells it.
13429    pub fn as_str(&self) -> &str {
13430        match self {
13431            Self::Ok => "ok",
13432            Self::Unavailable => "unavailable",
13433            Self::Other(value) => value,
13434        }
13435    }
13436}
13437
13438impl From<&str> for SourceStatus {
13439    fn from(value: &str) -> Self {
13440        match value {
13441            "ok" => Self::Ok,
13442            "unavailable" => Self::Unavailable,
13443            other => Self::Other(other.to_owned()),
13444        }
13445    }
13446}
13447
13448impl std::fmt::Display for SourceStatus {
13449    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13450        f.write_str(self.as_str())
13451    }
13452}
13453
13454impl AsRef<str> for SourceStatus {
13455    fn as_ref(&self) -> &str {
13456        self.as_str()
13457    }
13458}
13459
13460#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13461#[non_exhaustive]
13462pub struct SportLeaderboard {
13463    #[serde(default)]
13464    pub as_of: Option<String>,
13465    #[serde(default)]
13466    pub category: Option<String>,
13467    #[serde(default)]
13468    pub edge_average: Option<f64>,
13469    #[serde(default)]
13470    pub league: Option<SportLeaderboardLeague>,
13471    pub limit: i64,
13472    pub min_resolved: i64,
13473    pub rows: Vec<SportLeaderboardRowsItem>,
13474    pub sort: SportLeaderboardSort,
13475    pub sport: String,
13476    pub total_traders: i64,
13477    pub volume_scope: String,
13478}
13479
13480#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13481#[non_exhaustive]
13482pub struct SportLeaderboardLeague {
13483    pub name: String,
13484    pub ranked_traders: i64,
13485    pub slug: String,
13486}
13487
13488#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13489#[non_exhaustive]
13490pub struct SportLeaderboardRowsItem {
13491    pub address: String,
13492    #[serde(default)]
13493    pub cost: Option<f64>,
13494    #[serde(default)]
13495    pub edge_hold: Option<EdgeHold>,
13496    #[serde(default)]
13497    pub edge_skill: Option<f64>,
13498    #[serde(default)]
13499    pub grade: Option<Grade>,
13500    pub id: String,
13501    #[serde(default)]
13502    pub last_category_trade_at: Option<String>,
13503    pub losses: i64,
13504    pub n_resolved: i64,
13505    pub platform: String,
13506    #[serde(default)]
13507    pub pnl: Option<f64>,
13508    #[serde(default)]
13509    pub price_edge: Option<SportLeaderboardRowsItemPriceEdge>,
13510    pub rank: i64,
13511    #[serde(default)]
13512    pub roi: Option<f64>,
13513    #[serde(default)]
13514    pub username: Option<String>,
13515    #[serde(default)]
13516    pub volume: Option<f64>,
13517    #[serde(default)]
13518    pub win_rate: Option<f64>,
13519    #[serde(default)]
13520    pub win_rate_wilson_lb: Option<f64>,
13521    pub wins: i64,
13522}
13523
13524#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13525#[non_exhaustive]
13526pub struct SportLeaderboardRowsItemPriceEdge {
13527    pub avg_price: f64,
13528    pub edge: f64,
13529    pub edge_lower: f64,
13530    pub hit_rate: f64,
13531    pub markets: i64,
13532    pub status: SportLeaderboardRowsPriceEdgeStatus,
13533}
13534
13535/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13536#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13537#[non_exhaustive]
13538pub enum SportLeaderboardRowsPriceEdgeStatus {
13539    /// `ranked`
13540    #[serde(rename = "ranked")]
13541    Ranked,
13542    /// `too_few_markets`
13543    #[serde(rename = "too_few_markets")]
13544    TooFewMarkets,
13545    /// `sample_mismatch`
13546    #[serde(rename = "sample_mismatch")]
13547    SampleMismatch,
13548    /// A value this release does not know, kept as sent.
13549    #[serde(untagged)]
13550    Other(String),
13551}
13552
13553impl SportLeaderboardRowsPriceEdgeStatus {
13554    /// The value as the API spells it.
13555    pub fn as_str(&self) -> &str {
13556        match self {
13557            Self::Ranked => "ranked",
13558            Self::TooFewMarkets => "too_few_markets",
13559            Self::SampleMismatch => "sample_mismatch",
13560            Self::Other(value) => value,
13561        }
13562    }
13563}
13564
13565impl From<&str> for SportLeaderboardRowsPriceEdgeStatus {
13566    fn from(value: &str) -> Self {
13567        match value {
13568            "ranked" => Self::Ranked,
13569            "too_few_markets" => Self::TooFewMarkets,
13570            "sample_mismatch" => Self::SampleMismatch,
13571            other => Self::Other(other.to_owned()),
13572        }
13573    }
13574}
13575
13576impl std::fmt::Display for SportLeaderboardRowsPriceEdgeStatus {
13577    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13578        f.write_str(self.as_str())
13579    }
13580}
13581
13582impl AsRef<str> for SportLeaderboardRowsPriceEdgeStatus {
13583    fn as_ref(&self) -> &str {
13584        self.as_str()
13585    }
13586}
13587
13588/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13589#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13590#[non_exhaustive]
13591pub enum SportLeaderboardSort {
13592    /// `edge`
13593    #[serde(rename = "edge")]
13594    Edge,
13595    /// `pnl`
13596    #[serde(rename = "pnl")]
13597    Pnl,
13598    /// `win_rate`
13599    #[serde(rename = "win_rate")]
13600    WinRate,
13601    /// A value this release does not know, kept as sent.
13602    #[serde(untagged)]
13603    Other(String),
13604}
13605
13606impl SportLeaderboardSort {
13607    /// The value as the API spells it.
13608    pub fn as_str(&self) -> &str {
13609        match self {
13610            Self::Edge => "edge",
13611            Self::Pnl => "pnl",
13612            Self::WinRate => "win_rate",
13613            Self::Other(value) => value,
13614        }
13615    }
13616}
13617
13618impl From<&str> for SportLeaderboardSort {
13619    fn from(value: &str) -> Self {
13620        match value {
13621            "edge" => Self::Edge,
13622            "pnl" => Self::Pnl,
13623            "win_rate" => Self::WinRate,
13624            other => Self::Other(other.to_owned()),
13625        }
13626    }
13627}
13628
13629impl std::fmt::Display for SportLeaderboardSort {
13630    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13631        f.write_str(self.as_str())
13632    }
13633}
13634
13635impl AsRef<str> for SportLeaderboardSort {
13636    fn as_ref(&self) -> &str {
13637        self.as_str()
13638    }
13639}
13640
13641/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13642#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13643#[non_exhaustive]
13644pub enum State {
13645    /// `scheduled`
13646    #[serde(rename = "scheduled")]
13647    Scheduled,
13648    /// `live`
13649    #[serde(rename = "live")]
13650    Live,
13651    /// `paused`
13652    #[serde(rename = "paused")]
13653    Paused,
13654    /// `ended`
13655    #[serde(rename = "ended")]
13656    Ended,
13657    /// `postponed`
13658    #[serde(rename = "postponed")]
13659    Postponed,
13660    /// `cancelled`
13661    #[serde(rename = "cancelled")]
13662    Cancelled,
13663    /// `suspended`
13664    #[serde(rename = "suspended")]
13665    Suspended,
13666    /// `delayed`
13667    #[serde(rename = "delayed")]
13668    Delayed,
13669    /// `unknown`
13670    #[serde(rename = "unknown")]
13671    Unknown,
13672    /// A value this release does not know, kept as sent.
13673    #[serde(untagged)]
13674    Other(String),
13675}
13676
13677impl State {
13678    /// The value as the API spells it.
13679    pub fn as_str(&self) -> &str {
13680        match self {
13681            Self::Scheduled => "scheduled",
13682            Self::Live => "live",
13683            Self::Paused => "paused",
13684            Self::Ended => "ended",
13685            Self::Postponed => "postponed",
13686            Self::Cancelled => "cancelled",
13687            Self::Suspended => "suspended",
13688            Self::Delayed => "delayed",
13689            Self::Unknown => "unknown",
13690            Self::Other(value) => value,
13691        }
13692    }
13693}
13694
13695impl From<&str> for State {
13696    fn from(value: &str) -> Self {
13697        match value {
13698            "scheduled" => Self::Scheduled,
13699            "live" => Self::Live,
13700            "paused" => Self::Paused,
13701            "ended" => Self::Ended,
13702            "postponed" => Self::Postponed,
13703            "cancelled" => Self::Cancelled,
13704            "suspended" => Self::Suspended,
13705            "delayed" => Self::Delayed,
13706            "unknown" => Self::Unknown,
13707            other => Self::Other(other.to_owned()),
13708        }
13709    }
13710}
13711
13712impl std::fmt::Display for State {
13713    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13714        f.write_str(self.as_str())
13715    }
13716}
13717
13718impl AsRef<str> for State {
13719    fn as_ref(&self) -> &str {
13720        self.as_str()
13721    }
13722}
13723
13724/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13725#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13726#[non_exhaustive]
13727pub enum Status {
13728    /// `live`
13729    #[serde(rename = "live")]
13730    Live,
13731    /// `insufficient`
13732    #[serde(rename = "insufficient")]
13733    Insufficient,
13734    /// `stale`
13735    #[serde(rename = "stale")]
13736    Stale,
13737    /// `unknown`
13738    #[serde(rename = "unknown")]
13739    Unknown,
13740    /// `degraded`
13741    #[serde(rename = "degraded")]
13742    Degraded,
13743    /// A value this release does not know, kept as sent.
13744    #[serde(untagged)]
13745    Other(String),
13746}
13747
13748impl Status {
13749    /// The value as the API spells it.
13750    pub fn as_str(&self) -> &str {
13751        match self {
13752            Self::Live => "live",
13753            Self::Insufficient => "insufficient",
13754            Self::Stale => "stale",
13755            Self::Unknown => "unknown",
13756            Self::Degraded => "degraded",
13757            Self::Other(value) => value,
13758        }
13759    }
13760}
13761
13762impl From<&str> for Status {
13763    fn from(value: &str) -> Self {
13764        match value {
13765            "live" => Self::Live,
13766            "insufficient" => Self::Insufficient,
13767            "stale" => Self::Stale,
13768            "unknown" => Self::Unknown,
13769            "degraded" => Self::Degraded,
13770            other => Self::Other(other.to_owned()),
13771        }
13772    }
13773}
13774
13775impl std::fmt::Display for Status {
13776    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13777        f.write_str(self.as_str())
13778    }
13779}
13780
13781impl AsRef<str> for Status {
13782    fn as_ref(&self) -> &str {
13783        self.as_str()
13784    }
13785}
13786
13787/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13788#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13789#[non_exhaustive]
13790pub enum Storage {
13791    /// `durable`
13792    #[serde(rename = "durable")]
13793    Durable,
13794    /// `ephemeral`
13795    #[serde(rename = "ephemeral")]
13796    Ephemeral,
13797    /// A value this release does not know, kept as sent.
13798    #[serde(untagged)]
13799    Other(String),
13800}
13801
13802impl Storage {
13803    /// The value as the API spells it.
13804    pub fn as_str(&self) -> &str {
13805        match self {
13806            Self::Durable => "durable",
13807            Self::Ephemeral => "ephemeral",
13808            Self::Other(value) => value,
13809        }
13810    }
13811}
13812
13813impl From<&str> for Storage {
13814    fn from(value: &str) -> Self {
13815        match value {
13816            "durable" => Self::Durable,
13817            "ephemeral" => Self::Ephemeral,
13818            other => Self::Other(other.to_owned()),
13819        }
13820    }
13821}
13822
13823impl std::fmt::Display for Storage {
13824    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13825        f.write_str(self.as_str())
13826    }
13827}
13828
13829impl AsRef<str> for Storage {
13830    fn as_ref(&self) -> &str {
13831        self.as_str()
13832    }
13833}
13834
13835/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13836#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13837#[non_exhaustive]
13838pub enum Strategy {
13839    /// `category_focused`
13840    #[serde(rename = "category_focused")]
13841    CategoryFocused,
13842    /// `diversified`
13843    #[serde(rename = "diversified")]
13844    Diversified,
13845    /// `high_activity`
13846    #[serde(rename = "high_activity")]
13847    HighActivity,
13848    /// `mixed`
13849    #[serde(rename = "mixed")]
13850    Mixed,
13851    /// `two_sided`
13852    #[serde(rename = "two_sided")]
13853    TwoSided,
13854    /// `unclassified`
13855    #[serde(rename = "unclassified")]
13856    Unclassified,
13857    /// A value this release does not know, kept as sent.
13858    #[serde(untagged)]
13859    Other(String),
13860}
13861
13862impl Strategy {
13863    /// The value as the API spells it.
13864    pub fn as_str(&self) -> &str {
13865        match self {
13866            Self::CategoryFocused => "category_focused",
13867            Self::Diversified => "diversified",
13868            Self::HighActivity => "high_activity",
13869            Self::Mixed => "mixed",
13870            Self::TwoSided => "two_sided",
13871            Self::Unclassified => "unclassified",
13872            Self::Other(value) => value,
13873        }
13874    }
13875}
13876
13877impl From<&str> for Strategy {
13878    fn from(value: &str) -> Self {
13879        match value {
13880            "category_focused" => Self::CategoryFocused,
13881            "diversified" => Self::Diversified,
13882            "high_activity" => Self::HighActivity,
13883            "mixed" => Self::Mixed,
13884            "two_sided" => Self::TwoSided,
13885            "unclassified" => Self::Unclassified,
13886            other => Self::Other(other.to_owned()),
13887        }
13888    }
13889}
13890
13891impl std::fmt::Display for Strategy {
13892    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13893        f.write_str(self.as_str())
13894    }
13895}
13896
13897impl AsRef<str> for Strategy {
13898    fn as_ref(&self) -> &str {
13899        self.as_str()
13900    }
13901}
13902
13903/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13904#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13905#[non_exhaustive]
13906pub enum StreakTier {
13907    /// `hot`
13908    #[serde(rename = "hot")]
13909    Hot,
13910    /// `rising`
13911    #[serde(rename = "rising")]
13912    Rising,
13913    /// `neutral`
13914    #[serde(rename = "neutral")]
13915    Neutral,
13916    /// `cooling`
13917    #[serde(rename = "cooling")]
13918    Cooling,
13919    /// `cold`
13920    #[serde(rename = "cold")]
13921    Cold,
13922    /// A value this release does not know, kept as sent.
13923    #[serde(untagged)]
13924    Other(String),
13925}
13926
13927impl StreakTier {
13928    /// The value as the API spells it.
13929    pub fn as_str(&self) -> &str {
13930        match self {
13931            Self::Hot => "hot",
13932            Self::Rising => "rising",
13933            Self::Neutral => "neutral",
13934            Self::Cooling => "cooling",
13935            Self::Cold => "cold",
13936            Self::Other(value) => value,
13937        }
13938    }
13939}
13940
13941impl From<&str> for StreakTier {
13942    fn from(value: &str) -> Self {
13943        match value {
13944            "hot" => Self::Hot,
13945            "rising" => Self::Rising,
13946            "neutral" => Self::Neutral,
13947            "cooling" => Self::Cooling,
13948            "cold" => Self::Cold,
13949            other => Self::Other(other.to_owned()),
13950        }
13951    }
13952}
13953
13954impl std::fmt::Display for StreakTier {
13955    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13956        f.write_str(self.as_str())
13957    }
13958}
13959
13960impl AsRef<str> for StreakTier {
13961    fn as_ref(&self) -> &str {
13962        self.as_str()
13963    }
13964}
13965
13966#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13967pub struct SubmitWhaleDatasetBody {
13968    pub from: String,
13969    pub to: String,
13970    /// Raw provider condition id or mkt_-prefixed id.
13971    #[serde(default, skip_serializing_if = "Option::is_none")]
13972    pub condition_id: Option<String>,
13973    /// USD minimum, normalized to cents like replay.
13974    #[serde(default, skip_serializing_if = "Option::is_none")]
13975    pub min_size: Option<f64>,
13976}
13977
13978/// A value this release does not know is kept in `Other`, so a new value never fails a response.
13979#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13980#[non_exhaustive]
13981pub enum SuspicionTrack {
13982    /// `whale`
13983    #[serde(rename = "whale")]
13984    Whale,
13985    /// `fresh_conviction`
13986    #[serde(rename = "fresh_conviction")]
13987    FreshConviction,
13988    /// `sliced_position`
13989    #[serde(rename = "sliced_position")]
13990    SlicedPosition,
13991    /// A value this release does not know, kept as sent.
13992    #[serde(untagged)]
13993    Other(String),
13994}
13995
13996impl SuspicionTrack {
13997    /// The value as the API spells it.
13998    pub fn as_str(&self) -> &str {
13999        match self {
14000            Self::Whale => "whale",
14001            Self::FreshConviction => "fresh_conviction",
14002            Self::SlicedPosition => "sliced_position",
14003            Self::Other(value) => value,
14004        }
14005    }
14006}
14007
14008impl From<&str> for SuspicionTrack {
14009    fn from(value: &str) -> Self {
14010        match value {
14011            "whale" => Self::Whale,
14012            "fresh_conviction" => Self::FreshConviction,
14013            "sliced_position" => Self::SlicedPosition,
14014            other => Self::Other(other.to_owned()),
14015        }
14016    }
14017}
14018
14019impl std::fmt::Display for SuspicionTrack {
14020    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14021        f.write_str(self.as_str())
14022    }
14023}
14024
14025impl AsRef<str> for SuspicionTrack {
14026    fn as_ref(&self) -> &str {
14027        self.as_str()
14028    }
14029}
14030
14031#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14032#[non_exhaustive]
14033pub struct SuspiciousTrade {
14034    /// Prefixed ID (rf_...).
14035    pub id: String,
14036    /// Stored score that met the live flag threshold.
14037    pub suspicion_score: f64,
14038    /// The live scorer persists one threshold class.
14039    pub severity: String,
14040    pub trader: SuspiciousTradeTrader,
14041    pub market: SuspiciousTradeMarket,
14042    pub scores: SuspiciousTradeScores,
14043    /// Stored whale_alerts.suspicion_signals JSON from the scorer.
14044    pub evidence: serde_json::Value,
14045    /// Stored trade timestamp.
14046    pub created_at: String,
14047}
14048
14049/// `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).
14050#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14051#[non_exhaustive]
14052pub struct SuspiciousTradeFlaggedData {
14053    /// Numeric id of the flagged trade, a JSON number. It is the `id` that `GET /api/v1/large-trades/{id}` accepts.
14054    pub trade_id: i64,
14055    /// Address of the wallet that made the trade.
14056    pub wallet: String,
14057    /// 0xinsider's numeric id for the wallet.
14058    pub trader_id: i64,
14059    /// Polymarket condition id of the market.
14060    pub condition_id: String,
14061    /// The suspicion score, 0 to 100, that crossed the threshold.
14062    pub suspicion_score: f64,
14063    /// The scoring track that raised the flag.
14064    pub track: SuspicionTrack,
14065    /// Outcome side the flagged fill took.
14066    pub side: SuspiciousTradeFlaggedDataSide,
14067    /// Share count of the flagged fill.
14068    pub size: f64,
14069    /// Fill price of the flagged trade.
14070    pub price: f64,
14071}
14072
14073/// A value this release does not know is kept in `Other`, so a new value never fails a response.
14074#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
14075#[non_exhaustive]
14076pub enum SuspiciousTradeFlaggedDataSide {
14077    /// `yes`
14078    #[serde(rename = "yes")]
14079    Yes,
14080    /// `no`
14081    #[serde(rename = "no")]
14082    No,
14083    /// A value this release does not know, kept as sent.
14084    #[serde(untagged)]
14085    Other(String),
14086}
14087
14088impl SuspiciousTradeFlaggedDataSide {
14089    /// The value as the API spells it.
14090    pub fn as_str(&self) -> &str {
14091        match self {
14092            Self::Yes => "yes",
14093            Self::No => "no",
14094            Self::Other(value) => value,
14095        }
14096    }
14097}
14098
14099impl From<&str> for SuspiciousTradeFlaggedDataSide {
14100    fn from(value: &str) -> Self {
14101        match value {
14102            "yes" => Self::Yes,
14103            "no" => Self::No,
14104            other => Self::Other(other.to_owned()),
14105        }
14106    }
14107}
14108
14109impl std::fmt::Display for SuspiciousTradeFlaggedDataSide {
14110    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14111        f.write_str(self.as_str())
14112    }
14113}
14114
14115impl AsRef<str> for SuspiciousTradeFlaggedDataSide {
14116    fn as_ref(&self) -> &str {
14117        self.as_str()
14118    }
14119}
14120
14121#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14122#[non_exhaustive]
14123pub struct SuspiciousTradeMarket {
14124    pub id: String,
14125    pub condition_id: String,
14126    /// Canonical market question when available.
14127    #[serde(default)]
14128    pub title: Option<String>,
14129}
14130
14131#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14132#[non_exhaustive]
14133pub struct SuspiciousTradeScores {
14134    /// Null because the live scorer does not record this component.
14135    #[serde(default)]
14136    pub timing: Option<f64>,
14137    /// Null because the live scorer does not record this component.
14138    #[serde(default)]
14139    pub edge: Option<f64>,
14140    /// Numeric evidence.size when recorded; otherwise null.
14141    #[serde(default)]
14142    pub size: Option<f64>,
14143    /// Numeric evidence.fresh when recorded; otherwise null.
14144    #[serde(default)]
14145    pub fresh_wallet: Option<f64>,
14146}
14147
14148#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14149#[non_exhaustive]
14150pub struct SuspiciousTradeTrader {
14151    pub id: String,
14152    pub address: String,
14153    #[serde(default)]
14154    pub username: Option<String>,
14155}
14156
14157/// A value this release does not know is kept in `Other`, so a new value never fails a response.
14158#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
14159#[non_exhaustive]
14160pub enum Sweep {
14161    /// `win`
14162    #[serde(rename = "win")]
14163    Win,
14164    /// `loss`
14165    #[serde(rename = "loss")]
14166    Loss,
14167    /// A value this release does not know, kept as sent.
14168    #[serde(untagged)]
14169    Other(String),
14170}
14171
14172impl Sweep {
14173    /// The value as the API spells it.
14174    pub fn as_str(&self) -> &str {
14175        match self {
14176            Self::Win => "win",
14177            Self::Loss => "loss",
14178            Self::Other(value) => value,
14179        }
14180    }
14181}
14182
14183impl From<&str> for Sweep {
14184    fn from(value: &str) -> Self {
14185        match value {
14186            "win" => Self::Win,
14187            "loss" => Self::Loss,
14188            other => Self::Other(other.to_owned()),
14189        }
14190    }
14191}
14192
14193impl std::fmt::Display for Sweep {
14194    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14195        f.write_str(self.as_str())
14196    }
14197}
14198
14199impl AsRef<str> for Sweep {
14200    fn as_ref(&self) -> &str {
14201        self.as_str()
14202    }
14203}
14204
14205/// 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. 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.
14206#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14207#[non_exhaustive]
14208pub struct TennisPoints {
14209    pub source: String,
14210    /// API-Tennis match ID. This is not a Polymarket market or event ID.
14211    pub match_key: i64,
14212    /// API-Tennis player IDs in the same first/second order as live_score.scores. These are not Polymarket team IDs.
14213    pub player_keys: Vec<i64>,
14214    /// Current-game point values in first/second order. Read strings, including A for advantage and numeric tiebreak points. Missing points are not zero.
14215    pub points: Vec<String>,
14216    /// The serving player in live_score.scores display order. Omitted when API-Tennis does not identify the server.
14217    #[serde(default, skip_serializing_if = "Option::is_none")]
14218    pub serving_side: Option<ServingSide>,
14219    /// Orders only the tennis_points group for the same match. Never compare this with live_score.source_revision.
14220    pub source_revision: i64,
14221    /// When 0xinsider observed these API-Tennis facts. This is not a timestamp from the court.
14222    pub observed_at: String,
14223    /// Stop displaying the point group at this instant, even if the enclosing score remains fresh. The group expires 30 seconds after observed_at.
14224    pub expires_at: String,
14225    /// Current set number. Display points only while this matches the enclosing scoreboard, unless set_games is present.
14226    pub set_number: i64,
14227    /// Current-set games in first/second order. Display points only while these match the enclosing scoreboard, unless set_games is present.
14228    pub games: Vec<i64>,
14229    /// 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.
14230    #[serde(default, skip_serializing_if = "Option::is_none")]
14231    pub set_games: Option<Vec<Vec<i64>>>,
14232}
14233
14234/// 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.
14235#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14236#[non_exhaustive]
14237pub struct TennisRanking {
14238    /// Provider-reported singles rank.
14239    pub rank: i64,
14240    /// The player ranking tour.
14241    pub tour: TennisRankingTour,
14242    /// The standings provider.
14243    pub source: String,
14244    /// Successful snapshot retrieval time in UTC, not ranking publication date.
14245    pub observed_at: String,
14246    /// UTC deadline after which clients must hide this rank, including when an older game or pick response remains cached.
14247    pub expires_at: String,
14248}
14249
14250/// A value this release does not know is kept in `Other`, so a new value never fails a response.
14251#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
14252#[non_exhaustive]
14253pub enum TennisRankingTour {
14254    /// `atp`
14255    #[serde(rename = "atp")]
14256    Atp,
14257    /// `wta`
14258    #[serde(rename = "wta")]
14259    Wta,
14260    /// A value this release does not know, kept as sent.
14261    #[serde(untagged)]
14262    Other(String),
14263}
14264
14265impl TennisRankingTour {
14266    /// The value as the API spells it.
14267    pub fn as_str(&self) -> &str {
14268        match self {
14269            Self::Atp => "atp",
14270            Self::Wta => "wta",
14271            Self::Other(value) => value,
14272        }
14273    }
14274}
14275
14276impl From<&str> for TennisRankingTour {
14277    fn from(value: &str) -> Self {
14278        match value {
14279            "atp" => Self::Atp,
14280            "wta" => Self::Wta,
14281            other => Self::Other(other.to_owned()),
14282        }
14283    }
14284}
14285
14286impl std::fmt::Display for TennisRankingTour {
14287    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14288        f.write_str(self.as_str())
14289    }
14290}
14291
14292impl AsRef<str> for TennisRankingTour {
14293    fn as_ref(&self) -> &str {
14294        self.as_str()
14295    }
14296}
14297
14298/// A value this release does not know is kept in `Other`, so a new value never fails a response.
14299#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
14300#[non_exhaustive]
14301pub enum TimeBasis {
14302    /// `polymarket_gamma_closed_time`
14303    #[serde(rename = "polymarket_gamma_closed_time")]
14304    PolymarketGammaClosedTime,
14305    /// `observed_resolution`
14306    #[serde(rename = "observed_resolution")]
14307    ObservedResolution,
14308    /// A value this release does not know, kept as sent.
14309    #[serde(untagged)]
14310    Other(String),
14311}
14312
14313impl TimeBasis {
14314    /// The value as the API spells it.
14315    pub fn as_str(&self) -> &str {
14316        match self {
14317            Self::PolymarketGammaClosedTime => "polymarket_gamma_closed_time",
14318            Self::ObservedResolution => "observed_resolution",
14319            Self::Other(value) => value,
14320        }
14321    }
14322}
14323
14324impl From<&str> for TimeBasis {
14325    fn from(value: &str) -> Self {
14326        match value {
14327            "polymarket_gamma_closed_time" => Self::PolymarketGammaClosedTime,
14328            "observed_resolution" => Self::ObservedResolution,
14329            other => Self::Other(other.to_owned()),
14330        }
14331    }
14332}
14333
14334impl std::fmt::Display for TimeBasis {
14335    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14336        f.write_str(self.as_str())
14337    }
14338}
14339
14340impl AsRef<str> for TimeBasis {
14341    fn as_ref(&self) -> &str {
14342        self.as_str()
14343    }
14344}
14345
14346/// A value this release does not know is kept in `Other`, so a new value never fails a response.
14347#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
14348#[non_exhaustive]
14349pub enum Timeframe {
14350    /// `1h`
14351    #[serde(rename = "1h")]
14352    V1h,
14353    /// `4h`
14354    #[serde(rename = "4h")]
14355    V4h,
14356    /// `24h`
14357    #[serde(rename = "24h")]
14358    V24h,
14359    /// `7d`
14360    #[serde(rename = "7d")]
14361    V7d,
14362    /// A value this release does not know, kept as sent.
14363    #[serde(untagged)]
14364    Other(String),
14365}
14366
14367impl Timeframe {
14368    /// The value as the API spells it.
14369    pub fn as_str(&self) -> &str {
14370        match self {
14371            Self::V1h => "1h",
14372            Self::V4h => "4h",
14373            Self::V24h => "24h",
14374            Self::V7d => "7d",
14375            Self::Other(value) => value,
14376        }
14377    }
14378}
14379
14380impl From<&str> for Timeframe {
14381    fn from(value: &str) -> Self {
14382        match value {
14383            "1h" => Self::V1h,
14384            "4h" => Self::V4h,
14385            "24h" => Self::V24h,
14386            "7d" => Self::V7d,
14387            other => Self::Other(other.to_owned()),
14388        }
14389    }
14390}
14391
14392impl std::fmt::Display for Timeframe {
14393    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14394        f.write_str(self.as_str())
14395    }
14396}
14397
14398impl AsRef<str> for Timeframe {
14399    fn as_ref(&self) -> &str {
14400        self.as_str()
14401    }
14402}
14403
14404/// A value this release does not know is kept in `Other`, so a new value never fails a response.
14405#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
14406#[non_exhaustive]
14407pub enum Tour {
14408    /// `atp`
14409    #[serde(rename = "atp")]
14410    Atp,
14411    /// `wta`
14412    #[serde(rename = "wta")]
14413    Wta,
14414    /// `itf`
14415    #[serde(rename = "itf")]
14416    Itf,
14417    /// A value this release does not know, kept as sent.
14418    #[serde(untagged)]
14419    Other(String),
14420}
14421
14422impl Tour {
14423    /// The value as the API spells it.
14424    pub fn as_str(&self) -> &str {
14425        match self {
14426            Self::Atp => "atp",
14427            Self::Wta => "wta",
14428            Self::Itf => "itf",
14429            Self::Other(value) => value,
14430        }
14431    }
14432}
14433
14434impl From<&str> for Tour {
14435    fn from(value: &str) -> Self {
14436        match value {
14437            "atp" => Self::Atp,
14438            "wta" => Self::Wta,
14439            "itf" => Self::Itf,
14440            other => Self::Other(other.to_owned()),
14441        }
14442    }
14443}
14444
14445impl std::fmt::Display for Tour {
14446    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14447        f.write_str(self.as_str())
14448    }
14449}
14450
14451impl AsRef<str> for Tour {
14452    fn as_ref(&self) -> &str {
14453        self.as_str()
14454    }
14455}
14456
14457#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14458#[non_exhaustive]
14459pub struct Trader {
14460    /// Prefixed ID (trd_...).
14461    pub id: String,
14462    pub address: String,
14463    #[serde(default, skip_serializing_if = "Option::is_none")]
14464    pub username: Option<String>,
14465    #[serde(default, skip_serializing_if = "Option::is_none")]
14466    pub grade: Option<Grade>,
14467    /// Hot-streak tier (trailing-7d cross-sectional percentile); a separate axis from the all-time grade. Omitted when there is no recent activity.
14468    #[serde(default, skip_serializing_if = "Option::is_none")]
14469    pub streak_tier: Option<StreakTier>,
14470    #[serde(default, skip_serializing_if = "Option::is_none")]
14471    pub score: Option<f64>,
14472    /// Optional forecast score on the documented display scale. Null when unavailable.
14473    #[serde(default, skip_serializing_if = "Option::is_none")]
14474    pub forecast_score: Option<f64>,
14475    /// Optional measured forecast context. Missing values remain unavailable rather than being inferred.
14476    #[serde(default, skip_serializing_if = "Option::is_none")]
14477    pub forecast_evidence: Option<f64>,
14478    #[serde(default, skip_serializing_if = "Option::is_none")]
14479    pub rank: Option<i64>,
14480    pub pnl: TraderPnlSummary,
14481    /// 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).
14482    pub stats: TraderStats,
14483    #[serde(default, skip_serializing_if = "Option::is_none")]
14484    pub strategy: Option<TraderStrategy>,
14485    /// 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.
14486    #[serde(default, skip_serializing_if = "Option::is_none")]
14487    pub category_strengths: Option<serde_json::Map<String, serde_json::Value>>,
14488    /// 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.
14489    #[serde(default, skip_serializing_if = "Option::is_none")]
14490    pub quant_metrics: Option<TraderQuantMetrics>,
14491    /// 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.
14492    #[serde(default, skip_serializing_if = "Option::is_none")]
14493    pub last_active: Option<String>,
14494    /// 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.
14495    #[serde(default, skip_serializing_if = "Option::is_none")]
14496    pub synced_at: Option<String>,
14497    /// synced, unknown, or pending.
14498    #[serde(default, skip_serializing_if = "Option::is_none")]
14499    pub sync_status: Option<String>,
14500    /// 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.
14501    pub data_quality: DataQuality,
14502    /// Field-level trust metadata. Present only when expand=trust or expand[]=trust is requested.
14503    #[serde(default, skip_serializing_if = "Option::is_none")]
14504    pub trust: Option<TraderTrust>,
14505    /// 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.
14506    #[serde(default, skip_serializing_if = "Option::is_none")]
14507    pub category_records: Option<Vec<CategorySkillV2>>,
14508    #[serde(default, skip_serializing_if = "Option::is_none")]
14509    pub category_skill_model: Option<CategorySkillModelReadiness>,
14510    /// 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.
14511    #[serde(default, skip_serializing_if = "Option::is_none")]
14512    pub price_edge: Option<TraderPriceEdge>,
14513    /// 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.
14514    #[serde(default, skip_serializing_if = "Option::is_none")]
14515    pub breakdowns: Option<TraderBreakdowns>,
14516}
14517
14518/// 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.
14519#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14520#[non_exhaustive]
14521pub struct TraderBreakdowns {
14522    pub hourly_performance: TraderHourlyPerformance,
14523    pub time_breakdowns: TraderTimeBreakdowns,
14524    /// 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.
14525    #[serde(default)]
14526    pub risk_metrics: Option<TraderRiskMetrics>,
14527    pub entry_price_analysis: TraderEntryPriceAnalysis,
14528}
14529
14530#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14531#[non_exhaustive]
14532pub struct TraderCategoryRecord {
14533    /// Canonical category bucket, for example Soccer, Esports, Tennis. Esports is one bucket, and the Esports record carries its per-game records in games.
14534    pub category: String,
14535    /// Markets in this category the wallet closed with a profit.
14536    pub wins: i64,
14537    /// 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.
14538    pub decided: i64,
14539    /// wins / decided in [0,1], truncated to four decimals. Null when status is not_enough_data.
14540    #[serde(default)]
14541    pub win_rate: Option<f64>,
14542    /// 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.
14543    pub status: TraderEsportsGameRecordStatus,
14544    /// 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.
14545    #[serde(default, skip_serializing_if = "Option::is_none")]
14546    pub games: Option<Vec<TraderEsportsGameRecord>>,
14547}
14548
14549#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14550#[non_exhaustive]
14551pub struct TraderCategoryRecords {
14552    /// Prefixed trader id (trd_<wallet>).
14553    pub id: String,
14554    /// Resolved wallet address, lowercased.
14555    pub address: String,
14556    /// 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.
14557    pub basis: String,
14558    /// Decided markets a category needs before win_rate is served. Published so a caller can apply its own sample rule to the raw counts.
14559    pub min_decided_for_win_rate: i64,
14560    /// When the served records were last rebuilt (RFC3339, Z): the newest stamp among every row served, game rows included, which the daily rebuild writes in one transaction. Null when the wallet has no record at all.
14561    #[serde(default)]
14562    pub computed_at: Option<String>,
14563    /// 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.
14564    pub records: Vec<TraderCategoryRecord>,
14565}
14566
14567#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14568#[non_exhaustive]
14569pub struct TraderContext {
14570    pub trader: Trader,
14571    /// 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.
14572    #[serde(default, skip_serializing_if = "Option::is_none")]
14573    pub position_summary: Option<TraderContextPositionSummary>,
14574    /// 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.
14575    #[serde(default)]
14576    pub data_as_of: Option<String>,
14577    /// 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).
14578    pub freshness_note: String,
14579}
14580
14581/// 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.
14582#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14583#[non_exhaustive]
14584pub struct TraderContextPositionSummary {
14585    /// Polymarket's count of the markets the wallet traded, every category, when known; null when the provider total is unavailable.
14586    #[serde(default)]
14587    pub markets_total: Option<i64>,
14588    /// Markets with locally synced position rows.
14589    pub markets_synced: i64,
14590    /// 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.
14591    pub markets_pruned: i64,
14592    /// 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.
14593    pub markets_unstored: i64,
14594    /// 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.
14595    pub markets_combo: i64,
14596    /// Synced markets the wallet has settled: it closed its position by selling out, or the market resolved. Its P&L there is final.
14597    pub markets_resolved: i64,
14598    /// 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).
14599    pub markets_open: i64,
14600    /// 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.
14601    pub sync_coverage: f64,
14602    /// 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.
14603    pub synced_realized_pnl: f64,
14604    /// 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.
14605    pub total_realized_pnl: f64,
14606    /// 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).
14607    pub unrealized_mtm: f64,
14608    /// Cost basis (USD) currently tied up in open positions in synced sports and esports markets (#32119).
14609    pub cost_basis_locked: f64,
14610    /// 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.
14611    #[serde(default)]
14612    pub resolved_win_rate: Option<f64>,
14613    /// Settled markets that closed at positive realized P&L: the win-rate numerator. Additive; null only on a summary cached before the field existed.
14614    #[serde(default)]
14615    pub resolved_wins: Option<i64>,
14616    /// 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.
14617    #[serde(default)]
14618    pub resolved_decided: Option<i64>,
14619    /// 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.
14620    #[serde(default)]
14621    pub as_of: Option<String>,
14622}
14623
14624/// Results by the entry price the wallet paid for the side it held, over its sports and esports markets with a known held entry price.
14625#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14626#[non_exhaustive]
14627pub struct TraderEntryPriceAnalysis {
14628    /// One bucket per price band that has a market, in bucket_order.
14629    pub buckets: Vec<TraderEntryPriceBucket>,
14630    /// The bucket with the highest win rate among buckets of at least 3 markets. null when no bucket has 3.
14631    #[serde(default)]
14632    pub best_bucket: Option<String>,
14633    /// The bucket with the lowest win rate among buckets of at least 3 markets. null when no bucket has 3.
14634    #[serde(default)]
14635    pub worst_bucket: Option<String>,
14636}
14637
14638/// One entry-price band. Each measure is an analytic value: read state before value.
14639#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14640#[non_exhaustive]
14641pub struct TraderEntryPriceBucket {
14642    /// The band: $0.01-$0.19, $0.20-$0.39, $0.40-$0.59, $0.60-$0.79 or $0.80-$0.99. The last also holds any price below $0.01.
14643    pub bucket: String,
14644    /// Display position, 0 first, from the lowest price up.
14645    pub bucket_order: i64,
14646    /// Markets in the band.
14647    pub markets: AnalyticInteger,
14648    /// Of those, the markets that made money.
14649    pub wins: AnalyticInteger,
14650    /// wins over decided markets (a nonzero P&L), as a percentage 0-100.
14651    pub win_rate: AnalyticNumber,
14652    /// Realized P&L of the band's markets, USD.
14653    pub total_pnl: AnalyticNumber,
14654    /// Mean realized P&L of a market in the band, USD.
14655    pub avg_pnl: AnalyticNumber,
14656}
14657
14658#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14659#[non_exhaustive]
14660pub struct TraderEsportsGameRecord {
14661    /// 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.
14662    pub game: String,
14663    /// 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.
14664    pub series_slug: String,
14665    /// Markets in this game the wallet closed with a profit.
14666    pub wins: i64,
14667    /// 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.
14668    pub decided: i64,
14669    /// wins / decided in [0,1], truncated to four decimals. Null when status is not_enough_data.
14670    #[serde(default)]
14671    pub win_rate: Option<f64>,
14672    /// 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.
14673    pub status: TraderEsportsGameRecordStatus,
14674}
14675
14676/// A value this release does not know is kept in `Other`, so a new value never fails a response.
14677#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
14678#[non_exhaustive]
14679pub enum TraderEsportsGameRecordStatus {
14680    /// `measured`
14681    #[serde(rename = "measured")]
14682    Measured,
14683    /// `not_enough_data`
14684    #[serde(rename = "not_enough_data")]
14685    NotEnoughData,
14686    /// A value this release does not know, kept as sent.
14687    #[serde(untagged)]
14688    Other(String),
14689}
14690
14691impl TraderEsportsGameRecordStatus {
14692    /// The value as the API spells it.
14693    pub fn as_str(&self) -> &str {
14694        match self {
14695            Self::Measured => "measured",
14696            Self::NotEnoughData => "not_enough_data",
14697            Self::Other(value) => value,
14698        }
14699    }
14700}
14701
14702impl From<&str> for TraderEsportsGameRecordStatus {
14703    fn from(value: &str) -> Self {
14704        match value {
14705            "measured" => Self::Measured,
14706            "not_enough_data" => Self::NotEnoughData,
14707            other => Self::Other(other.to_owned()),
14708        }
14709    }
14710}
14711
14712impl std::fmt::Display for TraderEsportsGameRecordStatus {
14713    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14714        f.write_str(self.as_str())
14715    }
14716}
14717
14718impl AsRef<str> for TraderEsportsGameRecordStatus {
14719    fn as_ref(&self) -> &str {
14720        self.as_str()
14721    }
14722}
14723
14724#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14725#[non_exhaustive]
14726pub struct TraderExportArtifactManifest {
14727    /// Version of the artifact manifest contract.
14728    pub manifest_version: String,
14729    /// Serialization used for the decompressed content.
14730    pub format: Format,
14731    /// Stable schema identifier for the selected serialization.
14732    pub schema_version: SchemaVersion,
14733    /// Sections represented by the artifact. JSON and NDJSON carry the full envelope and trades; CSV carries trade rows only.
14734    pub coverage: Coverage,
14735    pub generation: TraderExportGeneration,
14736    /// Number of trade rows written.
14737    pub row_count: i64,
14738    /// Exact byte count of the decompressed content stream clients receive.
14739    pub content_size_bytes: i64,
14740    /// Lowercase SHA-256 of the decompressed content bytes.
14741    pub content_sha256: String,
14742    /// Exact byte count of the gzip-compressed bytes stored by the object provider.
14743    pub compressed_size_bytes: i64,
14744    /// Lowercase SHA-256 of the stored gzip bytes; the multipart ETag is not used as this checksum.
14745    pub compressed_sha256: String,
14746}
14747
14748#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14749#[non_exhaustive]
14750pub struct TraderExportCategoryWatermark {
14751    pub source: String,
14752    pub coverage: String,
14753    #[serde(default)]
14754    pub publication_fence: Option<String>,
14755    #[serde(default)]
14756    pub data_as_of: Option<String>,
14757}
14758
14759#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14760#[non_exhaustive]
14761pub struct TraderExportGeneration {
14762    /// Opaque generation identity selected for the coherent read snapshot.
14763    pub id: String,
14764    pub selected_at: String,
14765    pub consistency: String,
14766    pub source_watermarks: TraderExportSourceWatermarks,
14767    /// 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.
14768    #[serde(default, skip_serializing_if = "Option::is_none")]
14769    pub product_scope: Option<String>,
14770}
14771
14772#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14773#[non_exhaustive]
14774pub struct TraderExportJob {
14775    pub object: String,
14776    pub data: TraderExportJobData,
14777    pub meta: ResponseMeta,
14778}
14779
14780#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14781#[non_exhaustive]
14782pub struct TraderExportJobData {
14783    pub job_id: i64,
14784    /// 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.
14785    pub status: TraderExportJobDataStatus,
14786    pub format: Format,
14787    /// 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.
14788    #[serde(default)]
14789    pub total_trades: Option<i64>,
14790    /// Trade rows written so far; equals total_trades once the file is read.
14791    #[serde(default)]
14792    pub processed_trades: Option<i64>,
14793    #[serde(default)]
14794    pub file_size: Option<i64>,
14795    #[serde(default)]
14796    pub error: Option<String>,
14797    /// True when status never changes again (ready, failed, expired, cancelled). Stop polling.
14798    pub terminal: bool,
14799    /// 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.
14800    pub next_action: NextAction,
14801    /// 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.
14802    #[serde(default, skip_serializing_if = "Option::is_none")]
14803    pub poll_after_s: Option<i64>,
14804    pub created_at: String,
14805    /// When the worker last claimed the job; null while queued.
14806    #[serde(default)]
14807    pub started_at: Option<String>,
14808    /// When the file became downloadable. null before ready, and on jobs finalized before this field existed.
14809    #[serde(default)]
14810    pub ready_at: Option<String>,
14811    #[serde(default)]
14812    pub failed_at: Option<String>,
14813    /// 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.
14814    pub expires_at: String,
14815    /// When the job became expired; null until then.
14816    #[serde(default)]
14817    pub expired_at: Option<String>,
14818    /// 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.
14819    #[serde(default)]
14820    pub data_as_of: Option<String>,
14821    /// 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.
14822    #[serde(default)]
14823    pub cancel_requested_at: Option<String>,
14824    /// When the job reached cancelled; null until then.
14825    #[serde(default)]
14826    pub cancelled_at: Option<String>,
14827    /// 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.
14828    pub attempt: i64,
14829    /// The job fails when attempt reaches this.
14830    pub max_attempts: i64,
14831    /// Present only while status is ready: the stored object's identity, so a client can check the download it receives.
14832    #[serde(default, skip_serializing_if = "Option::is_none")]
14833    pub artifact: Option<TraderExportJobDataArtifact>,
14834}
14835
14836/// Present only while status is ready: the stored object's identity, so a client can check the download it receives.
14837#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14838#[non_exhaustive]
14839pub struct TraderExportJobDataArtifact {
14840    /// Stable identity for this completed export artifact; unchanged when a temporary download URL is renewed.
14841    pub artifact_id: String,
14842    /// The storage ETag of the object.
14843    #[serde(default)]
14844    pub etag: Option<String>,
14845    /// Bytes on the wire (gzip); file_size is the decompressed size.
14846    #[serde(default)]
14847    pub compressed_size_bytes: Option<i64>,
14848    pub content_type: ContentType,
14849    pub content_encoding: String,
14850    /// Immutable manifest for artifacts generated with manifest support; null on historical artifacts written before this contract.
14851    #[serde(default)]
14852    pub manifest: Option<TraderExportArtifactManifest>,
14853}
14854
14855/// A value this release does not know is kept in `Other`, so a new value never fails a response.
14856#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
14857#[non_exhaustive]
14858pub enum TraderExportJobDataStatus {
14859    /// `queued`
14860    #[serde(rename = "queued")]
14861    Queued,
14862    /// `running`
14863    #[serde(rename = "running")]
14864    Running,
14865    /// `ready`
14866    #[serde(rename = "ready")]
14867    Ready,
14868    /// `failed`
14869    #[serde(rename = "failed")]
14870    Failed,
14871    /// `reconcile_required`
14872    #[serde(rename = "reconcile_required")]
14873    ReconcileRequired,
14874    /// `expired`
14875    #[serde(rename = "expired")]
14876    Expired,
14877    /// `cancel_requested`
14878    #[serde(rename = "cancel_requested")]
14879    CancelRequested,
14880    /// `cancelled`
14881    #[serde(rename = "cancelled")]
14882    Cancelled,
14883    /// A value this release does not know, kept as sent.
14884    #[serde(untagged)]
14885    Other(String),
14886}
14887
14888impl TraderExportJobDataStatus {
14889    /// The value as the API spells it.
14890    pub fn as_str(&self) -> &str {
14891        match self {
14892            Self::Queued => "queued",
14893            Self::Running => "running",
14894            Self::Ready => "ready",
14895            Self::Failed => "failed",
14896            Self::ReconcileRequired => "reconcile_required",
14897            Self::Expired => "expired",
14898            Self::CancelRequested => "cancel_requested",
14899            Self::Cancelled => "cancelled",
14900            Self::Other(value) => value,
14901        }
14902    }
14903}
14904
14905impl From<&str> for TraderExportJobDataStatus {
14906    fn from(value: &str) -> Self {
14907        match value {
14908            "queued" => Self::Queued,
14909            "running" => Self::Running,
14910            "ready" => Self::Ready,
14911            "failed" => Self::Failed,
14912            "reconcile_required" => Self::ReconcileRequired,
14913            "expired" => Self::Expired,
14914            "cancel_requested" => Self::CancelRequested,
14915            "cancelled" => Self::Cancelled,
14916            other => Self::Other(other.to_owned()),
14917        }
14918    }
14919}
14920
14921impl std::fmt::Display for TraderExportJobDataStatus {
14922    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14923        f.write_str(self.as_str())
14924    }
14925}
14926
14927impl AsRef<str> for TraderExportJobDataStatus {
14928    fn as_ref(&self) -> &str {
14929        self.as_str()
14930    }
14931}
14932
14933#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14934#[non_exhaustive]
14935pub struct TraderExportPnlWatermark {
14936    pub source: String,
14937    pub coverage: String,
14938    #[serde(default)]
14939    pub revision: Option<i64>,
14940    #[serde(default)]
14941    pub observed_at: Option<String>,
14942}
14943
14944#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14945#[non_exhaustive]
14946pub struct TraderExportPositionWatermark {
14947    pub source: String,
14948    pub coverage: String,
14949    #[serde(default)]
14950    pub generation: Option<i64>,
14951    #[serde(default)]
14952    pub data_as_of: Option<String>,
14953}
14954
14955#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14956#[non_exhaustive]
14957pub struct TraderExportSnapshot {
14958    pub address: String,
14959    /// 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.
14960    pub product_scope: String,
14961    pub generated_at: String,
14962    pub source_range: ExportSourceRange,
14963    pub completeness: ExportCompleteness,
14964    pub reconciliation: ExportVolumeReconciliation,
14965    pub counts: ExportCounts,
14966    pub large_export_policy: LargeExportPolicy,
14967}
14968
14969#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14970#[non_exhaustive]
14971pub struct TraderExportSourceWatermarks {
14972    pub positions: TraderExportPositionWatermark,
14973    pub pnl: TraderExportPnlWatermark,
14974    pub categories: TraderExportCategoryWatermark,
14975    pub trades: TraderExportTradeWatermark,
14976}
14977
14978#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14979#[non_exhaustive]
14980pub struct TraderExportTradeWatermark {
14981    pub source: String,
14982    /// 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.
14983    pub coverage: String,
14984    /// Trade rows the file holds, counted in the same read snapshot as the rows.
14985    pub rows: i64,
14986    #[serde(default)]
14987    pub first_activity_date: Option<String>,
14988}
14989
14990#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14991#[non_exhaustive]
14992pub struct TraderGradeAt {
14993    /// Prefixed trader id (trd_<wallet>).
14994    pub id: String,
14995    /// Resolved wallet address, lowercased.
14996    pub address: String,
14997    /// Requested event or decision time.
14998    pub as_of: String,
14999    /// graded has a proven grade; ungraded is a proven null grade; unknown has no valid historical observation.
15000    pub status: GradeAtTradeStatus,
15001    /// Grade only when status is graded; null otherwise.
15002    #[serde(default)]
15003    pub grade: Option<Grade>,
15004    /// First proven visibility instant for this trader. Null when no observation exists. Earlier times remain unknown.
15005    #[serde(default)]
15006    pub available_from: Option<String>,
15007    /// Proof row when status is graded or ungraded. Null when history is unknown.
15008    #[serde(default)]
15009    pub observation: Option<TraderGradeAtObservation>,
15010}
15011
15012/// Proof row when status is graded or ungraded. Null when history is unknown.
15013#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15014#[non_exhaustive]
15015pub struct TraderGradeAtObservation {
15016    /// Immutable grade_forward_history observation id.
15017    pub id: i64,
15018    /// 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.
15019    #[serde(default)]
15020    pub previous_observation_id: Option<i64>,
15021    /// Lower bound: the grade writer had started the transition at this instant.
15022    pub observed_at: String,
15023    /// Upper bound: a later snapshot confirmed the observation was committed. This is not an exact commit timestamp.
15024    pub published_by: String,
15025    /// Writer-proven model family, such as grading. Null when unknown.
15026    #[serde(default)]
15027    pub model_version: Option<String>,
15028    /// Exact writer build SHA when recorded. Null on old and non-model observations.
15029    #[serde(default)]
15030    pub model_build_sha: Option<String>,
15031    /// 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.
15032    #[serde(default)]
15033    pub source_observed_by: Option<String>,
15034}
15035
15036/// P&L and win rate by the UTC hour of the wallet's first trade in each settled sports or esports market.
15037#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15038#[non_exhaustive]
15039pub struct TraderHourlyPerformance {
15040    /// One entry per UTC hour that has a settled market; an hour with none is absent.
15041    pub entries: Vec<TraderHourlyPerformanceEntriesItem>,
15042    /// The hour with the highest win_rate. null when no entry exists.
15043    #[serde(default)]
15044    pub best_hour: Option<i64>,
15045    /// best_hour's win_rate, percentage 0-100. null exactly when best_hour is.
15046    #[serde(default)]
15047    pub best_win_rate: Option<f64>,
15048    /// The hour with the lowest win_rate. null when no entry exists.
15049    #[serde(default)]
15050    pub worst_hour: Option<i64>,
15051    /// worst_hour's win_rate, percentage 0-100. null exactly when worst_hour is.
15052    #[serde(default)]
15053    pub worst_win_rate: Option<f64>,
15054    /// best_win_rate minus worst_win_rate, percentage points. null when either is null.
15055    #[serde(default)]
15056    pub spread_pp: Option<f64>,
15057    /// 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.
15058    pub is_approximate: bool,
15059}
15060
15061#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15062#[non_exhaustive]
15063pub struct TraderHourlyPerformanceEntriesItem {
15064    /// UTC hour of the first trade, 0-23.
15065    pub hour: i64,
15066    /// Settled markets first traded in this hour.
15067    pub markets: i64,
15068    /// Of those, the markets that made money at settlement.
15069    pub wins: i64,
15070    /// 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.
15071    pub win_rate: f64,
15072    /// Realized P&L of those markets, USD.
15073    pub total_pnl: f64,
15074    /// total_pnl over markets, USD.
15075    pub avg_pnl: f64,
15076}
15077
15078/// 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.
15079#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15080#[non_exhaustive]
15081pub struct TraderPnl {
15082    /// Prefixed trader ID (`trd_...`).
15083    pub id: String,
15084    /// 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.
15085    #[serde(default, skip_serializing_if = "Option::is_none")]
15086    pub view: Option<TraderPnlView>,
15087    /// 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.
15088    #[serde(default)]
15089    pub freshness_at: Option<String>,
15090    /// `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.
15091    pub series_status: DailyPnlSeriesStatus,
15092    /// 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).
15093    #[serde(default)]
15094    pub realized: Option<TraderPnlRealized>,
15095    /// 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.
15096    #[serde(default, skip_serializing_if = "Option::is_none")]
15097    pub entries: Option<Vec<TraderPnlEntriesItem>>,
15098    /// 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.
15099    #[serde(default, skip_serializing_if = "Option::is_none")]
15100    pub stats: Option<TraderPnlStats>,
15101    /// 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.
15102    #[serde(default, skip_serializing_if = "Option::is_none")]
15103    pub monthly: Option<Vec<TraderPnlMonthlyItem>>,
15104    /// 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`.
15105    #[serde(default, skip_serializing_if = "Option::is_none")]
15106    pub year_totals: Option<Vec<TraderPnlYearTotalsItem>>,
15107    /// 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.
15108    #[serde(default, skip_serializing_if = "Option::is_none")]
15109    pub drawdown: Option<Vec<TraderPnlDrawdownItem>>,
15110}
15111
15112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15113#[non_exhaustive]
15114pub struct TraderPnlDrawdownItem {
15115    pub date: String,
15116    pub cumulative_profit: f64,
15117    pub drawdown: f64,
15118}
15119
15120#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15121#[non_exhaustive]
15122pub struct TraderPnlEntriesItem {
15123    pub date: String,
15124    /// 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.
15125    #[serde(default, skip_serializing_if = "Option::is_none")]
15126    pub markets_traded: Option<i64>,
15127    /// 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.
15128    #[serde(default, skip_serializing_if = "Option::is_none")]
15129    pub total_volume: Option<f64>,
15130    /// Running sum of daily_change through this day.
15131    #[serde(default, skip_serializing_if = "Option::is_none")]
15132    pub cumulative_profit: Option<f64>,
15133    /// The same running sum as cumulative_profit.
15134    #[serde(default, skip_serializing_if = "Option::is_none")]
15135    pub total_pnl: Option<f64>,
15136    /// 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.
15137    pub daily_change: f64,
15138}
15139
15140/// 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.
15141#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15142#[non_exhaustive]
15143pub struct TraderPnlExact {
15144    /// 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.
15145    pub realized: ExactDecimal,
15146}
15147
15148/// 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.
15149#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15150#[non_exhaustive]
15151pub struct TraderPnlInScope {
15152    /// 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.
15153    pub basis: String,
15154    /// Sports and esports realized P&L in USD, display-safe. null when the split basis has no published realized figure to split.
15155    #[serde(default)]
15156    pub realized_pnl: Option<f64>,
15157    /// Sports and esports markets the wallet has traded, any status.
15158    pub markets: i64,
15159    /// Of those, the settled markets: the wallet closed its position by selling out, or the market resolved. Its P&L there is final.
15160    pub markets_resolved: i64,
15161    /// Share of decided sports and esports markets the wallet won, 0 to 1. null with no decided market.
15162    #[serde(default)]
15163    pub win_rate: Option<f64>,
15164    /// 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).
15165    pub markets_out_of_scope: i64,
15166    /// When the record behind these figures was computed.
15167    pub as_of: String,
15168}
15169
15170#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15171#[non_exhaustive]
15172pub struct TraderPnlMonthlyItem {
15173    pub year: i64,
15174    pub month: i64,
15175    pub pnl: f64,
15176    /// 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.
15177    #[serde(default)]
15178    pub markets_traded: Option<i64>,
15179}
15180
15181/// 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).
15182#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15183#[non_exhaustive]
15184pub struct TraderPnlRealized {
15185    /// The rule behind realized_pnl, the same basis as pnl.in_scope.basis on GET /api/v1/trader/{address}.
15186    pub basis: TraderPnlRealizedBasis,
15187    /// 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.
15188    #[serde(default)]
15189    pub realized_pnl: Option<f64>,
15190    /// The sum of every day's daily_change over the full history, whatever from/to say.
15191    pub dated_pnl: f64,
15192    /// 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.
15193    #[serde(default)]
15194    pub undated_pnl: Option<f64>,
15195}
15196
15197/// A value this release does not know is kept in `Other`, so a new value never fails a response.
15198#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
15199#[non_exhaustive]
15200pub enum TraderPnlRealizedBasis {
15201    /// `polymarket_sports_esports_v1`
15202    #[serde(rename = "polymarket_sports_esports_v1")]
15203    PolymarketSportsEsportsV1,
15204    /// `sports_esports_split_v1`
15205    #[serde(rename = "sports_esports_split_v1")]
15206    SportsEsportsSplitV1,
15207    /// A value this release does not know, kept as sent.
15208    #[serde(untagged)]
15209    Other(String),
15210}
15211
15212impl TraderPnlRealizedBasis {
15213    /// The value as the API spells it.
15214    pub fn as_str(&self) -> &str {
15215        match self {
15216            Self::PolymarketSportsEsportsV1 => "polymarket_sports_esports_v1",
15217            Self::SportsEsportsSplitV1 => "sports_esports_split_v1",
15218            Self::Other(value) => value,
15219        }
15220    }
15221}
15222
15223impl From<&str> for TraderPnlRealizedBasis {
15224    fn from(value: &str) -> Self {
15225        match value {
15226            "polymarket_sports_esports_v1" => Self::PolymarketSportsEsportsV1,
15227            "sports_esports_split_v1" => Self::SportsEsportsSplitV1,
15228            other => Self::Other(other.to_owned()),
15229        }
15230    }
15231}
15232
15233impl std::fmt::Display for TraderPnlRealizedBasis {
15234    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15235        f.write_str(self.as_str())
15236    }
15237}
15238
15239impl AsRef<str> for TraderPnlRealizedBasis {
15240    fn as_ref(&self) -> &str {
15241        self.as_str()
15242    }
15243}
15244
15245/// 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.
15246#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15247#[non_exhaustive]
15248pub struct TraderPnlStats {
15249    pub all: TraderPnlStatsAll,
15250    pub d90: TraderPnlStatsD90,
15251    pub d30: TraderPnlStatsD30,
15252    pub d7: TraderPnlStatsD7,
15253}
15254
15255#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15256#[non_exhaustive]
15257pub struct TraderPnlStatsAll {
15258    pub current: f64,
15259    pub change: f64,
15260    pub change_pct: f64,
15261    pub best_day: f64,
15262    #[serde(default, skip_serializing_if = "Option::is_none")]
15263    pub best_day_date: Option<String>,
15264    pub worst_day: f64,
15265    #[serde(default, skip_serializing_if = "Option::is_none")]
15266    pub worst_day_date: Option<String>,
15267    pub win_days: i64,
15268    pub loss_days: i64,
15269    pub avg_day: f64,
15270    pub rebase_anchor: f64,
15271}
15272
15273#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15274#[non_exhaustive]
15275pub struct TraderPnlStatsD30 {
15276    pub current: f64,
15277    pub change: f64,
15278    pub change_pct: f64,
15279    pub best_day: f64,
15280    #[serde(default, skip_serializing_if = "Option::is_none")]
15281    pub best_day_date: Option<String>,
15282    pub worst_day: f64,
15283    #[serde(default, skip_serializing_if = "Option::is_none")]
15284    pub worst_day_date: Option<String>,
15285    pub win_days: i64,
15286    pub loss_days: i64,
15287    pub avg_day: f64,
15288    pub rebase_anchor: f64,
15289}
15290
15291#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15292#[non_exhaustive]
15293pub struct TraderPnlStatsD7 {
15294    pub current: f64,
15295    pub change: f64,
15296    pub change_pct: f64,
15297    pub best_day: f64,
15298    #[serde(default, skip_serializing_if = "Option::is_none")]
15299    pub best_day_date: Option<String>,
15300    pub worst_day: f64,
15301    #[serde(default, skip_serializing_if = "Option::is_none")]
15302    pub worst_day_date: Option<String>,
15303    pub win_days: i64,
15304    pub loss_days: i64,
15305    pub avg_day: f64,
15306    pub rebase_anchor: f64,
15307}
15308
15309#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15310#[non_exhaustive]
15311pub struct TraderPnlStatsD90 {
15312    pub current: f64,
15313    pub change: f64,
15314    pub change_pct: f64,
15315    pub best_day: f64,
15316    #[serde(default, skip_serializing_if = "Option::is_none")]
15317    pub best_day_date: Option<String>,
15318    pub worst_day: f64,
15319    #[serde(default, skip_serializing_if = "Option::is_none")]
15320    pub worst_day_date: Option<String>,
15321    pub win_days: i64,
15322    pub loss_days: i64,
15323    pub avg_day: f64,
15324    pub rebase_anchor: f64,
15325}
15326
15327#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15328#[non_exhaustive]
15329pub struct TraderPnlSummary {
15330    /// 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.
15331    #[serde(default, skip_serializing_if = "Option::is_none")]
15332    pub total: Option<f64>,
15333    /// 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.
15334    #[serde(default, skip_serializing_if = "Option::is_none")]
15335    pub net_total: Option<f64>,
15336    /// 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.
15337    #[serde(default, skip_serializing_if = "Option::is_none")]
15338    pub correction: Option<PnlCorrection>,
15339    /// 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.
15340    #[serde(default, skip_serializing_if = "Option::is_none")]
15341    pub correction_pending: Option<bool>,
15342    /// 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.
15343    #[serde(default, skip_serializing_if = "Option::is_none")]
15344    pub realized: Option<f64>,
15345    /// 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.
15346    #[serde(default, skip_serializing_if = "Option::is_none")]
15347    pub unrealized: Option<f64>,
15348    /// Deprecated since 2026-10-27 and never sent: its one member was the lossless counterpart of the retired pnl.realized (#29830).
15349    #[serde(default, skip_serializing_if = "Option::is_none")]
15350    pub exact: Option<TraderPnlExact>,
15351    /// 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).
15352    #[serde(default, skip_serializing_if = "Option::is_none")]
15353    pub in_scope: Option<TraderPnlInScope>,
15354}
15355
15356/// 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.
15357#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15358#[non_exhaustive]
15359pub struct TraderPnlView {
15360    /// Inclusive UTC lower bound applied to the daily series; null when the request left the series unbounded below.
15361    #[serde(default)]
15362    pub from: Option<String>,
15363    /// Inclusive UTC upper bound applied to the daily series; null when the request left the series unbounded above.
15364    #[serde(default)]
15365    pub to: Option<String>,
15366    /// Sections this body carries, in the order the object publishes them, whatever order the query listed.
15367    pub sections: Vec<Sections>,
15368    /// 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.
15369    pub entries_total: i64,
15370    /// 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.
15371    pub entries_in_window: i64,
15372    /// 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.
15373    #[serde(default)]
15374    pub anchor: Option<TraderPnlViewAnchor>,
15375}
15376
15377/// 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.
15378#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15379#[non_exhaustive]
15380pub struct TraderPnlViewAnchor {
15381    pub date: String,
15382    /// Cumulative profit carried into the window; null when the stored point has none, the same nullability entries[].cumulative_profit has.
15383    #[serde(default)]
15384    pub cumulative_profit: Option<f64>,
15385    /// Cumulative total P&L carried into the window; null on the same terms.
15386    #[serde(default)]
15387    pub total_pnl: Option<f64>,
15388    /// 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).
15389    #[serde(default)]
15390    pub drawdown: Option<f64>,
15391}
15392
15393#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15394#[non_exhaustive]
15395pub struct TraderPnlYearTotalsItem {
15396    pub year: i64,
15397    pub pnl: f64,
15398}
15399
15400/// 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.
15401#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15402#[non_exhaustive]
15403pub struct TraderPriceEdge {
15404    /// Settled sports and esports markets of $20 or more at a known entry price that the edge is measured over.
15405    pub markets: i64,
15406    /// Share of those markets whose bought side won, 0-1.
15407    pub hit_rate: f64,
15408    /// Mean entry price paid, 0-1.
15409    pub avg_price: f64,
15410    /// hit_rate minus avg_price, full precision, before any shrink.
15411    pub edge: f64,
15412    /// 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.
15413    pub status: SportLeaderboardRowsPriceEdgeStatus,
15414    /// 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.
15415    #[serde(default, skip_serializing_if = "Option::is_none")]
15416    pub shrunk_edge: Option<f64>,
15417    /// 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.
15418    #[serde(default, skip_serializing_if = "Option::is_none")]
15419    pub field_average: Option<f64>,
15420}
15421
15422/// 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.
15423#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15424#[non_exhaustive]
15425pub struct TraderQuantMetrics {
15426    /// Trader smart score on a 0..100 display scale; higher is stronger. Null when unavailable.
15427    #[serde(default)]
15428    pub smart_score: Option<f64>,
15429    /// 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.
15430    #[serde(default)]
15431    pub copy_score: Option<f64>,
15432    /// Sharpe ratio over the trailing 30 days (risk-adjusted return; higher is better). Magnitude can be large for small samples. null when insufficient history.
15433    #[serde(default)]
15434    pub sharpe_30d: Option<f64>,
15435    /// Sharpe ratio over the trailing 7 days (risk-adjusted return; higher is better). null when insufficient history.
15436    #[serde(default)]
15437    pub sharpe_7d: Option<f64>,
15438    /// Gross profit divided by gross loss; greater than 1 is profitable. Capped at 1000 when there are effectively no losses. null when insufficient history.
15439    #[serde(default)]
15440    pub profit_factor: Option<f64>,
15441    /// 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.
15442    #[serde(default)]
15443    pub edge_consistency: Option<f64>,
15444    /// Cross-sectional percentile rank of the trader's Sharpe ratio versus all traders, 0-100. null when insufficient history.
15445    #[serde(default)]
15446    pub sharpe_percentile: Option<f64>,
15447    /// Cross-sectional percentile rank of profit factor versus all traders, 0-100. null when insufficient history.
15448    #[serde(default)]
15449    pub pf_percentile: Option<f64>,
15450    /// Cross-sectional percentile rank of edge consistency versus all traders, 0-100. null when insufficient history.
15451    #[serde(default)]
15452    pub consistency_percentile: Option<f64>,
15453}
15454
15455/// 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.
15456#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15457#[non_exhaustive]
15458pub struct TraderRiskMetrics {
15459    /// Mean cost basis of a position, USD.
15460    pub avg_position_size: AnalyticNumber,
15461    /// Median cost basis of a position, USD.
15462    pub median_position_size: AnalyticNumber,
15463    /// Largest cost basis of a position, USD.
15464    pub max_position_size: AnalyticNumber,
15465    /// Population standard deviation of the cost basis, USD.
15466    pub position_size_stddev: AnalyticNumber,
15467    /// Sports and esports positions with trades.
15468    pub total_positions: i64,
15469    /// Positions whose cost is more than twice the mean.
15470    pub large_position_count: i64,
15471    /// 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.
15472    pub concentration: AnalyticNumber,
15473}
15474
15475/// 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).
15476#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15477#[non_exhaustive]
15478pub struct TraderStats {
15479    /// 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.
15480    #[serde(default, skip_serializing_if = "Option::is_none")]
15481    pub markets_traded: Option<i64>,
15482    /// 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.
15483    #[serde(default, skip_serializing_if = "Option::is_none")]
15484    pub win_rate: Option<f64>,
15485    /// 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.
15486    #[serde(default, skip_serializing_if = "Option::is_none")]
15487    pub daily_win_rate: Option<f64>,
15488    /// 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).
15489    #[serde(default, skip_serializing_if = "Option::is_none")]
15490    pub total_volume: Option<f64>,
15491    /// Additive lossless counterpart to `total_volume`, present exactly when it is.
15492    #[serde(default, skip_serializing_if = "Option::is_none")]
15493    pub exact: Option<TraderStatsExact>,
15494}
15495
15496/// Lossless counterparts for trader statistics. The object is present exactly when stats.total_volume is.
15497#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15498#[non_exhaustive]
15499pub struct TraderStatsExact {
15500    /// 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.
15501    pub total_volume: ExactDecimal,
15502}
15503
15504#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15505#[non_exhaustive]
15506pub struct TraderStrategy {
15507    /// 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.
15508    pub strategy_type: String,
15509    #[serde(default, skip_serializing_if = "Option::is_none")]
15510    pub description: Option<String>,
15511    #[serde(default, skip_serializing_if = "Option::is_none")]
15512    pub confidence: Option<f64>,
15513}
15514
15515/// `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).
15516#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15517#[non_exhaustive]
15518pub struct TraderSyncedData {
15519    /// 0xinsider's numeric id for the wallet.
15520    pub trader_id: i64,
15521    /// Proxy wallet address.
15522    pub wallet: String,
15523}
15524
15525/// One band of a time breakdown.
15526#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15527#[non_exhaustive]
15528pub struct TraderTimeBreakdownBand {
15529    /// The band's label.
15530    pub category_value: String,
15531    /// Markets with a realized P&L in the band.
15532    pub n_markets: i64,
15533    /// Resolved markets that made money over resolved markets with a nonzero P&L, 0-1. null when none is decided.
15534    #[serde(default)]
15535    pub win_rate: Option<f64>,
15536    /// total_pnl over n_markets, USD.
15537    #[serde(default)]
15538    pub expectancy: Option<f64>,
15539    /// Gross profit over gross loss. null when the band has no loss.
15540    #[serde(default)]
15541    pub profit_factor: Option<f64>,
15542    /// Realized P&L of the band's markets, USD.
15543    #[serde(default)]
15544    pub total_pnl: Option<f64>,
15545}
15546
15547/// 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.
15548#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15549#[non_exhaustive]
15550pub struct TraderTimeBreakdowns {
15551    /// 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.
15552    pub by_duration: Vec<TraderTimeBreakdownBand>,
15553    /// 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.
15554    pub by_hour_bucket: Vec<TraderTimeBreakdownBand>,
15555    /// 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.
15556    pub insights: std::collections::BTreeMap<String, String>,
15557}
15558
15559/// Field-level trust metadata returned only when GET /api/v1/trader/{address} includes expand=trust.
15560#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15561#[non_exhaustive]
15562pub struct TraderTrust {
15563    /// Since 2026-10-27 always not_computed: pnl.total is retired and never sent (#29830). The key stays so the object keeps its shape.
15564    pub total_pnl: TrustMetadata,
15565    /// 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.
15566    pub realized_pnl: TrustMetadata,
15567    /// 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.
15568    pub net_total_pnl: TrustMetadata,
15569    /// Deprecated since 2026-10-27 and never sent: it was present only with pnl.correction, which is retired (#29830).
15570    #[serde(default, skip_serializing_if = "Option::is_none")]
15571    pub pnl_correction: Option<TrustMetadata>,
15572    pub unrealized_pnl: TrustMetadata,
15573    /// 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).
15574    pub markets_traded: TrustMetadata,
15575    /// Computed, owned by trader_product_scope_records (win_rate) and dated by the record's computed_at, since 2026-10-27 (#29830).
15576    pub win_rate: TrustMetadata,
15577    /// 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.
15578    pub daily_win_rate: TrustMetadata,
15579    /// Computed, owned by trader_trade_daily_rollups (in_scope_volume_total) and dated by traders.last_synced, since 2026-10-27 (#29830).
15580    pub total_volume: TrustMetadata,
15581    pub grade: TrustMetadata,
15582    pub score: TrustMetadata,
15583    pub forecast_score: TrustMetadata,
15584    pub forecast_evidence: TrustMetadata,
15585    pub rank: TrustMetadata,
15586    pub streak_tier: TrustMetadata,
15587    pub strategy: TrustMetadata,
15588    pub category_strengths: TrustMetadata,
15589    pub quant_metrics: TrustMetadata,
15590    pub last_active: TrustMetadata,
15591    pub synced_at: TrustMetadata,
15592    pub sync_status: TrustMetadata,
15593    pub category_records: TrustMetadata,
15594    pub category_skill_model: TrustMetadata,
15595}
15596
15597#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15598#[non_exhaustive]
15599pub struct TrendingWallet {
15600    /// Prefixed trader ID (`trd_...`).
15601    pub id: String,
15602    pub address: String,
15603    /// 1-based rank within the full ranked set (stable across pages).
15604    pub rank: i64,
15605    #[serde(default, skip_serializing_if = "Option::is_none")]
15606    pub username: Option<String>,
15607    /// Official Polymarket avatar URL (profileImage).
15608    #[serde(default, skip_serializing_if = "Option::is_none")]
15609    pub profile_image_url: Option<String>,
15610    /// Real provider platform; surfaced, never coerced. Polymarket only.
15611    pub platform: String,
15612    /// 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.
15613    pub trending_pnl_usd: f64,
15614    /// 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.
15615    #[serde(default, skip_serializing_if = "Option::is_none")]
15616    pub window_volume_usd: Option<f64>,
15617    /// 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.
15618    #[serde(default, skip_serializing_if = "Option::is_none")]
15619    pub window_volume_shares: Option<f64>,
15620    pub window_markets_traded: i64,
15621    /// Distinct in-window UTC trade days from our trades (0 if the winner is not in our DB).
15622    pub window_trade_days: i64,
15623    /// 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).
15624    #[serde(default, skip_serializing_if = "Option::is_none")]
15625    pub grade: Option<Grade>,
15626    /// Hot-streak tier (trailing-7d cross-sectional percentile). Omitted when there is no recent activity.
15627    #[serde(default, skip_serializing_if = "Option::is_none")]
15628    pub streak_tier: Option<StreakTier>,
15629    /// 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.
15630    #[serde(default, skip_serializing_if = "Option::is_none")]
15631    pub in_scope_realized_pnl: Option<f64>,
15632    /// 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.
15633    #[serde(default, skip_serializing_if = "Option::is_none")]
15634    pub all_time_pnl_usd: Option<f64>,
15635    /// 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.
15636    #[serde(default, skip_serializing_if = "Option::is_none")]
15637    pub pnl_correction: Option<PnlCorrection>,
15638    #[serde(default, skip_serializing_if = "Option::is_none")]
15639    pub all_time_score: Option<f64>,
15640    #[serde(default, skip_serializing_if = "Option::is_none")]
15641    pub last_synced: Option<String>,
15642    /// 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.
15643    pub daily_pnl_series: Vec<TrendingWalletDailyPnlSeriesItem>,
15644    /// `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.
15645    pub daily_pnl_series_status: DailyPnlSeriesStatus,
15646}
15647
15648#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15649#[non_exhaustive]
15650pub struct TrendingWalletDailyPnlSeriesItem {
15651    pub date: String,
15652    pub pnl_usd: f64,
15653}
15654
15655/// Whether the described value or result set is complete for its stated contract.
15656#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15657#[non_exhaustive]
15658pub struct TrustCompleteness {
15659    pub status: TrustCompletenessStatus,
15660    #[serde(default, skip_serializing_if = "Option::is_none")]
15661    pub detail: Option<String>,
15662}
15663
15664/// A value this release does not know is kept in `Other`, so a new value never fails a response.
15665#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
15666#[non_exhaustive]
15667pub enum TrustCompletenessStatus {
15668    /// `complete`
15669    #[serde(rename = "complete")]
15670    Complete,
15671    /// `partial`
15672    #[serde(rename = "partial")]
15673    Partial,
15674    /// `not_computed`
15675    #[serde(rename = "not_computed")]
15676    NotComputed,
15677    /// `not_applicable`
15678    #[serde(rename = "not_applicable")]
15679    NotApplicable,
15680    /// `unavailable`
15681    #[serde(rename = "unavailable")]
15682    Unavailable,
15683    /// A value this release does not know, kept as sent.
15684    #[serde(untagged)]
15685    Other(String),
15686}
15687
15688impl TrustCompletenessStatus {
15689    /// The value as the API spells it.
15690    pub fn as_str(&self) -> &str {
15691        match self {
15692            Self::Complete => "complete",
15693            Self::Partial => "partial",
15694            Self::NotComputed => "not_computed",
15695            Self::NotApplicable => "not_applicable",
15696            Self::Unavailable => "unavailable",
15697            Self::Other(value) => value,
15698        }
15699    }
15700}
15701
15702impl From<&str> for TrustCompletenessStatus {
15703    fn from(value: &str) -> Self {
15704        match value {
15705            "complete" => Self::Complete,
15706            "partial" => Self::Partial,
15707            "not_computed" => Self::NotComputed,
15708            "not_applicable" => Self::NotApplicable,
15709            "unavailable" => Self::Unavailable,
15710            other => Self::Other(other.to_owned()),
15711        }
15712    }
15713}
15714
15715impl std::fmt::Display for TrustCompletenessStatus {
15716    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15717        f.write_str(self.as_str())
15718    }
15719}
15720
15721impl AsRef<str> for TrustCompletenessStatus {
15722    fn as_ref(&self) -> &str {
15723        self.as_str()
15724    }
15725}
15726
15727/// Freshness metadata for a trust-critical value. This is separate from transport cache fields in ResponseMeta.
15728#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15729#[non_exhaustive]
15730pub struct TrustFreshness {
15731    pub status: TrustFreshnessStatus,
15732    #[serde(default, skip_serializing_if = "Option::is_none")]
15733    pub as_of: Option<String>,
15734    #[serde(default, skip_serializing_if = "Option::is_none")]
15735    pub max_age_s: Option<i64>,
15736}
15737
15738/// A value this release does not know is kept in `Other`, so a new value never fails a response.
15739#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
15740#[non_exhaustive]
15741pub enum TrustFreshnessStatus {
15742    /// `fresh`
15743    #[serde(rename = "fresh")]
15744    Fresh,
15745    /// `refreshing`
15746    #[serde(rename = "refreshing")]
15747    Refreshing,
15748    /// `stale`
15749    #[serde(rename = "stale")]
15750    Stale,
15751    /// `not_live`
15752    #[serde(rename = "not_live")]
15753    NotLive,
15754    /// `unknown`
15755    #[serde(rename = "unknown")]
15756    Unknown,
15757    /// `unavailable`
15758    #[serde(rename = "unavailable")]
15759    Unavailable,
15760    /// A value this release does not know, kept as sent.
15761    #[serde(untagged)]
15762    Other(String),
15763}
15764
15765impl TrustFreshnessStatus {
15766    /// The value as the API spells it.
15767    pub fn as_str(&self) -> &str {
15768        match self {
15769            Self::Fresh => "fresh",
15770            Self::Refreshing => "refreshing",
15771            Self::Stale => "stale",
15772            Self::NotLive => "not_live",
15773            Self::Unknown => "unknown",
15774            Self::Unavailable => "unavailable",
15775            Self::Other(value) => value,
15776        }
15777    }
15778}
15779
15780impl From<&str> for TrustFreshnessStatus {
15781    fn from(value: &str) -> Self {
15782        match value {
15783            "fresh" => Self::Fresh,
15784            "refreshing" => Self::Refreshing,
15785            "stale" => Self::Stale,
15786            "not_live" => Self::NotLive,
15787            "unknown" => Self::Unknown,
15788            "unavailable" => Self::Unavailable,
15789            other => Self::Other(other.to_owned()),
15790        }
15791    }
15792}
15793
15794impl std::fmt::Display for TrustFreshnessStatus {
15795    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15796        f.write_str(self.as_str())
15797    }
15798}
15799
15800impl AsRef<str> for TrustFreshnessStatus {
15801    fn as_ref(&self) -> &str {
15802        self.as_str()
15803    }
15804}
15805
15806/// 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.
15807#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15808#[non_exhaustive]
15809pub struct TrustMetadata {
15810    pub source: TrustSource,
15811    pub freshness: TrustFreshness,
15812    pub reconciliation: TrustReconciliation,
15813    pub completeness: TrustCompleteness,
15814}
15815
15816/// How provider-owned facts were reconciled with stored/read-model values.
15817#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15818#[non_exhaustive]
15819pub struct TrustReconciliation {
15820    pub status: TrustReconciliationStatus,
15821    #[serde(default, skip_serializing_if = "Option::is_none")]
15822    pub detail: Option<String>,
15823}
15824
15825/// A value this release does not know is kept in `Other`, so a new value never fails a response.
15826#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
15827#[non_exhaustive]
15828pub enum TrustReconciliationStatus {
15829    /// `provider_backed`
15830    #[serde(rename = "provider_backed")]
15831    ProviderBacked,
15832    /// `db_mirror`
15833    #[serde(rename = "db_mirror")]
15834    DbMirror,
15835    /// `computed`
15836    #[serde(rename = "computed")]
15837    Computed,
15838    /// `partial`
15839    #[serde(rename = "partial")]
15840    Partial,
15841    /// `not_applicable`
15842    #[serde(rename = "not_applicable")]
15843    NotApplicable,
15844    /// `unavailable`
15845    #[serde(rename = "unavailable")]
15846    Unavailable,
15847    /// A value this release does not know, kept as sent.
15848    #[serde(untagged)]
15849    Other(String),
15850}
15851
15852impl TrustReconciliationStatus {
15853    /// The value as the API spells it.
15854    pub fn as_str(&self) -> &str {
15855        match self {
15856            Self::ProviderBacked => "provider_backed",
15857            Self::DbMirror => "db_mirror",
15858            Self::Computed => "computed",
15859            Self::Partial => "partial",
15860            Self::NotApplicable => "not_applicable",
15861            Self::Unavailable => "unavailable",
15862            Self::Other(value) => value,
15863        }
15864    }
15865}
15866
15867impl From<&str> for TrustReconciliationStatus {
15868    fn from(value: &str) -> Self {
15869        match value {
15870            "provider_backed" => Self::ProviderBacked,
15871            "db_mirror" => Self::DbMirror,
15872            "computed" => Self::Computed,
15873            "partial" => Self::Partial,
15874            "not_applicable" => Self::NotApplicable,
15875            "unavailable" => Self::Unavailable,
15876            other => Self::Other(other.to_owned()),
15877        }
15878    }
15879}
15880
15881impl std::fmt::Display for TrustReconciliationStatus {
15882    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15883        f.write_str(self.as_str())
15884    }
15885}
15886
15887impl AsRef<str> for TrustReconciliationStatus {
15888    fn as_ref(&self) -> &str {
15889        self.as_str()
15890    }
15891}
15892
15893/// 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.
15894#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15895#[non_exhaustive]
15896pub struct TrustSource {
15897    pub kind: TrustSourceKind,
15898    /// Provider, table/read-model, cache, or service that owns the value.
15899    pub owner: String,
15900    /// Provider field, DB column, or computed field name when applicable.
15901    #[serde(default, skip_serializing_if = "Option::is_none")]
15902    pub field: Option<String>,
15903}
15904
15905/// A value this release does not know is kept in `Other`, so a new value never fails a response.
15906#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
15907#[non_exhaustive]
15908pub enum TrustSourceKind {
15909    /// `provider`
15910    #[serde(rename = "provider")]
15911    Provider,
15912    /// `database`
15913    #[serde(rename = "database")]
15914    Database,
15915    /// `cache`
15916    #[serde(rename = "cache")]
15917    Cache,
15918    /// `computed`
15919    #[serde(rename = "computed")]
15920    Computed,
15921    /// `client_input`
15922    #[serde(rename = "client_input")]
15923    ClientInput,
15924    /// `unavailable`
15925    #[serde(rename = "unavailable")]
15926    Unavailable,
15927    /// A value this release does not know, kept as sent.
15928    #[serde(untagged)]
15929    Other(String),
15930}
15931
15932impl TrustSourceKind {
15933    /// The value as the API spells it.
15934    pub fn as_str(&self) -> &str {
15935        match self {
15936            Self::Provider => "provider",
15937            Self::Database => "database",
15938            Self::Cache => "cache",
15939            Self::Computed => "computed",
15940            Self::ClientInput => "client_input",
15941            Self::Unavailable => "unavailable",
15942            Self::Other(value) => value,
15943        }
15944    }
15945}
15946
15947impl From<&str> for TrustSourceKind {
15948    fn from(value: &str) -> Self {
15949        match value {
15950            "provider" => Self::Provider,
15951            "database" => Self::Database,
15952            "cache" => Self::Cache,
15953            "computed" => Self::Computed,
15954            "client_input" => Self::ClientInput,
15955            "unavailable" => Self::Unavailable,
15956            other => Self::Other(other.to_owned()),
15957        }
15958    }
15959}
15960
15961impl std::fmt::Display for TrustSourceKind {
15962    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15963        f.write_str(self.as_str())
15964    }
15965}
15966
15967impl AsRef<str> for TrustSourceKind {
15968    fn as_ref(&self) -> &str {
15969        self.as_str()
15970    }
15971}
15972
15973#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
15974pub struct UpdateWebhookRequest {
15975    #[serde(default, skip_serializing_if = "Option::is_none")]
15976    pub name: Option<String>,
15977    /// 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.
15978    #[serde(default, skip_serializing_if = "Option::is_none")]
15979    pub url: Option<String>,
15980    #[serde(default, skip_serializing_if = "Option::is_none")]
15981    pub event_types: Option<Vec<WebhookEventType>>,
15982    #[serde(default, skip_serializing_if = "Option::is_none")]
15983    pub trade_filters: Option<LargeTradeSubscriptionFilters>,
15984    #[serde(default, skip_serializing_if = "Option::is_none")]
15985    pub enabled: Option<bool>,
15986}
15987
15988#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15989#[non_exhaustive]
15990pub struct UpdateWebhookResponse {
15991    pub object: String,
15992    pub data: WebhookEndpoint,
15993    pub meta: ResponseMeta,
15994}
15995
15996#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15997#[non_exhaustive]
15998pub struct Usage {
15999    pub object: String,
16000    pub data: UsageData,
16001    pub meta: ResponseMeta,
16002}
16003
16004#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16005#[non_exhaustive]
16006pub struct UsageData {
16007    pub rate_limit: UsageDataRateLimit,
16008    /// UTC-day usage count. Current V1 has no daily hard cap, so limit and remaining are null rather than synthesized.
16009    pub daily_usage: UsageDataDailyUsage,
16010    /// 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.
16011    #[serde(default)]
16012    pub monthly_quota: Option<UsageDataMonthlyQuota>,
16013}
16014
16015/// UTC-day usage count. Current V1 has no daily hard cap, so limit and remaining are null rather than synthesized.
16016#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16017#[non_exhaustive]
16018pub struct UsageDataDailyUsage {
16019    pub used: i64,
16020    #[serde(default)]
16021    pub limit: Option<i64>,
16022    #[serde(default)]
16023    pub remaining: Option<i64>,
16024    pub reset_at: i64,
16025    pub window_seconds: i64,
16026}
16027
16028/// 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.
16029#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16030#[non_exhaustive]
16031pub struct UsageDataMonthlyQuota {
16032    /// Admitted requests so far this UTC calendar month.
16033    pub used: i64,
16034    /// Requests the account's plan includes per UTC calendar month: 500,000 for Pro, 2,000,000 for Max.
16035    pub limit: i64,
16036    pub remaining: i64,
16037    /// Unix seconds: the first instant of the next UTC calendar month.
16038    pub reset_at: i64,
16039    /// Unix seconds: from when request limit + 1 is refused for an account the quota binds.
16040    pub enforced_from: i64,
16041    /// Whether requests over this account's ceiling are refused right now: false before enforced_from and for an admin account.
16042    pub binding: bool,
16043    /// Pay as you go is on: requests over the quota keep answering and bill on a monthly invoice, up to ceiling.
16044    pub pay_as_you_go: bool,
16045    /// 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.
16046    #[serde(default)]
16047    pub ceiling: Option<i64>,
16048    /// 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.
16049    #[serde(default)]
16050    pub unavailable_reason: Option<String>,
16051}
16052
16053#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16054#[non_exhaustive]
16055pub struct UsageDataRateLimit {
16056    pub used: i64,
16057    /// 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.
16058    pub limit: i64,
16059    pub remaining: i64,
16060    pub reset_at: i64,
16061    pub window_seconds: i64,
16062}
16063
16064#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16065pub struct VerifyWebhookRequest {
16066    /// 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.
16067    pub verification_token: String,
16068}
16069
16070#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16071#[non_exhaustive]
16072pub struct VerifyWebhookResponse {
16073    pub object: String,
16074    pub data: WebhookEndpoint,
16075    pub meta: ResponseMeta,
16076}
16077
16078/// A value this release does not know is kept in `Other`, so a new value never fails a response.
16079#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
16080#[non_exhaustive]
16081pub enum View {
16082    /// `full`
16083    #[serde(rename = "full")]
16084    Full,
16085    /// `totals`
16086    #[serde(rename = "totals")]
16087    Totals,
16088    /// A value this release does not know, kept as sent.
16089    #[serde(untagged)]
16090    Other(String),
16091}
16092
16093impl View {
16094    /// The value as the API spells it.
16095    pub fn as_str(&self) -> &str {
16096        match self {
16097            Self::Full => "full",
16098            Self::Totals => "totals",
16099            Self::Other(value) => value,
16100        }
16101    }
16102}
16103
16104impl From<&str> for View {
16105    fn from(value: &str) -> Self {
16106        match value {
16107            "full" => Self::Full,
16108            "totals" => Self::Totals,
16109            other => Self::Other(other.to_owned()),
16110        }
16111    }
16112}
16113
16114impl std::fmt::Display for View {
16115    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16116        f.write_str(self.as_str())
16117    }
16118}
16119
16120impl AsRef<str> for View {
16121    fn as_ref(&self) -> &str {
16122        self.as_str()
16123    }
16124}
16125
16126/// `wallet_grade_changed` data (Pro and Max): a tracked wallet's grade moved on a re-grade.
16127#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16128#[non_exhaustive]
16129pub struct WalletGradeChangedData {
16130    /// Lowercased proxy wallet address.
16131    pub wallet: String,
16132    /// 0xinsider's numeric id for the wallet.
16133    pub trader_id: i64,
16134    /// The grade before the move. Never equal to `new_grade`.
16135    pub old_grade: Grade,
16136    pub new_grade: Grade,
16137    /// `upgrade` when `new_grade` is better than `old_grade`, else `downgrade`.
16138    pub direction: WalletGradeChangedDataDirection,
16139    /// Cohort skill index that drove the grade, 0 to 1.
16140    pub skill_index: f64,
16141    /// Final 0 to 100 score banded into the new grade.
16142    pub final_score: f64,
16143    /// The ranking date of the re-grade.
16144    pub date: String,
16145}
16146
16147/// A value this release does not know is kept in `Other`, so a new value never fails a response.
16148#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
16149#[non_exhaustive]
16150pub enum WalletGradeChangedDataDirection {
16151    /// `upgrade`
16152    #[serde(rename = "upgrade")]
16153    Upgrade,
16154    /// `downgrade`
16155    #[serde(rename = "downgrade")]
16156    Downgrade,
16157    /// A value this release does not know, kept as sent.
16158    #[serde(untagged)]
16159    Other(String),
16160}
16161
16162impl WalletGradeChangedDataDirection {
16163    /// The value as the API spells it.
16164    pub fn as_str(&self) -> &str {
16165        match self {
16166            Self::Upgrade => "upgrade",
16167            Self::Downgrade => "downgrade",
16168            Self::Other(value) => value,
16169        }
16170    }
16171}
16172
16173impl From<&str> for WalletGradeChangedDataDirection {
16174    fn from(value: &str) -> Self {
16175        match value {
16176            "upgrade" => Self::Upgrade,
16177            "downgrade" => Self::Downgrade,
16178            other => Self::Other(other.to_owned()),
16179        }
16180    }
16181}
16182
16183impl std::fmt::Display for WalletGradeChangedDataDirection {
16184    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16185        f.write_str(self.as_str())
16186    }
16187}
16188
16189impl AsRef<str> for WalletGradeChangedDataDirection {
16190    fn as_ref(&self) -> &str {
16191        self.as_str()
16192    }
16193}
16194
16195/// 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.
16196#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16197#[non_exhaustive]
16198pub struct WebhookDelivery {
16199    pub id: i64,
16200    pub object: String,
16201    /// Stable event id for this delivery; identical across retries of the same logical event.
16202    pub event_id: String,
16203    pub event_type: WebhookEventType,
16204    /// Delivery lifecycle state (e.g. pending, delivered, dead_letter).
16205    pub status: String,
16206    /// Number of delivery attempts made so far.
16207    pub attempt_count: i64,
16208    /// HTTP status code of the most recent delivery attempt. Omitted until a response (or transport error) has been recorded.
16209    #[serde(default, skip_serializing_if = "Option::is_none")]
16210    pub last_response_status: Option<i64>,
16211    /// Short description of the most recent delivery failure. Omitted when the last attempt succeeded or none has failed.
16212    #[serde(default, skip_serializing_if = "Option::is_none")]
16213    pub last_error: Option<String>,
16214    /// When the delivery was first accepted by the destination. Omitted until a delivery succeeds.
16215    #[serde(default, skip_serializing_if = "Option::is_none")]
16216    pub delivered_at: Option<String>,
16217    /// 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).
16218    #[serde(default)]
16219    pub next_attempt_at: Option<String>,
16220    /// 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.
16221    #[serde(default)]
16222    pub retry_schedule_reason: Option<RetryScheduleReason>,
16223    pub created_at: String,
16224}
16225
16226#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16227#[non_exhaustive]
16228pub struct WebhookEndpoint {
16229    pub id: i64,
16230    pub object: String,
16231    pub name: String,
16232    pub url: String,
16233    pub event_types: Vec<WebhookEventType>,
16234    pub trade_filters: LargeTradeSubscriptionFilters,
16235    pub status: WebhookStatus,
16236    #[serde(default)]
16237    pub verified_at: Option<String>,
16238    pub verification_token_expires_at: String,
16239    pub failure_count: i64,
16240    pub created_at: String,
16241    pub updated_at: String,
16242    pub retry_policy: WebhookRetryPolicy,
16243    pub secret_rotation: WebhookSecretRotation,
16244    /// 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.
16245    #[serde(default, skip_serializing_if = "Option::is_none")]
16246    pub signing_secret: Option<String>,
16247    #[serde(default, skip_serializing_if = "Option::is_none")]
16248    pub verification: Option<WebhookVerification>,
16249}
16250
16251/// 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.
16252#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16253#[non_exhaustive]
16254pub struct WebhookEventDescriptor {
16255    pub id: WebhookEventType,
16256    /// One-line description of when the event fires.
16257    pub description: String,
16258    /// Short description of the data payload object's shape.
16259    pub payload_shape: String,
16260    /// active: the event has a firing producer callsite. dormant: advertised and subscribable, but does not yet enqueue any delivery.
16261    pub status: WebhookEventDescriptorStatus,
16262}
16263
16264/// A value this release does not know is kept in `Other`, so a new value never fails a response.
16265#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
16266#[non_exhaustive]
16267pub enum WebhookEventDescriptorStatus {
16268    /// `active`
16269    #[serde(rename = "active")]
16270    Active,
16271    /// `dormant`
16272    #[serde(rename = "dormant")]
16273    Dormant,
16274    /// A value this release does not know, kept as sent.
16275    #[serde(untagged)]
16276    Other(String),
16277}
16278
16279impl WebhookEventDescriptorStatus {
16280    /// The value as the API spells it.
16281    pub fn as_str(&self) -> &str {
16282        match self {
16283            Self::Active => "active",
16284            Self::Dormant => "dormant",
16285            Self::Other(value) => value,
16286        }
16287    }
16288}
16289
16290impl From<&str> for WebhookEventDescriptorStatus {
16291    fn from(value: &str) -> Self {
16292        match value {
16293            "active" => Self::Active,
16294            "dormant" => Self::Dormant,
16295            other => Self::Other(other.to_owned()),
16296        }
16297    }
16298}
16299
16300impl std::fmt::Display for WebhookEventDescriptorStatus {
16301    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16302        f.write_str(self.as_str())
16303    }
16304}
16305
16306impl AsRef<str> for WebhookEventDescriptorStatus {
16307    fn as_ref(&self) -> &str {
16308        self.as_str()
16309    }
16310}
16311
16312/// A value this release does not know is kept in `Other`, so a new value never fails a response.
16313#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
16314#[non_exhaustive]
16315pub enum WebhookEventType {
16316    /// `large_trade_inserted_v2`
16317    #[serde(rename = "large_trade_inserted_v2")]
16318    LargeTradeInsertedV2,
16319    /// `large_trades_inserted`
16320    #[serde(rename = "large_trades_inserted")]
16321    LargeTradesInserted,
16322    /// `whale_trades_inserted`
16323    #[serde(rename = "whale_trades_inserted")]
16324    WhaleTradesInserted,
16325    /// `live_sports_updated`
16326    #[serde(rename = "live_sports_updated")]
16327    LiveSportsUpdated,
16328    /// `trader_synced`
16329    #[serde(rename = "trader_synced")]
16330    TraderSynced,
16331    /// `whale_trader_synced`
16332    #[serde(rename = "whale_trader_synced")]
16333    WhaleTraderSynced,
16334    /// `large_positions_updated`
16335    #[serde(rename = "large_positions_updated")]
16336    LargePositionsUpdated,
16337    /// `wallet_grade_changed`
16338    #[serde(rename = "wallet_grade_changed")]
16339    WalletGradeChanged,
16340    /// `suspicious_trade_flagged`
16341    #[serde(rename = "suspicious_trade_flagged")]
16342    SuspiciousTradeFlagged,
16343    /// `insider_radar_flag_raised`
16344    #[serde(rename = "insider_radar_flag_raised")]
16345    InsiderRadarFlagRaised,
16346    /// `sharp_money_flow_detected`
16347    #[serde(rename = "sharp_money_flow_detected")]
16348    SharpMoneyFlowDetected,
16349    /// `smart_money_flow_detected`
16350    #[serde(rename = "smart_money_flow_detected")]
16351    SmartMoneyFlowDetected,
16352    /// `export_job_ready`
16353    #[serde(rename = "export_job_ready")]
16354    ExportJobReady,
16355    /// `export_job_failed`
16356    #[serde(rename = "export_job_failed")]
16357    ExportJobFailed,
16358    /// `export_job_expired`
16359    #[serde(rename = "export_job_expired")]
16360    ExportJobExpired,
16361    /// `export_job_cancelled`
16362    #[serde(rename = "export_job_cancelled")]
16363    ExportJobCancelled,
16364    /// A value this release does not know, kept as sent.
16365    #[serde(untagged)]
16366    Other(String),
16367}
16368
16369impl WebhookEventType {
16370    /// The value as the API spells it.
16371    pub fn as_str(&self) -> &str {
16372        match self {
16373            Self::LargeTradeInsertedV2 => "large_trade_inserted_v2",
16374            Self::LargeTradesInserted => "large_trades_inserted",
16375            Self::WhaleTradesInserted => "whale_trades_inserted",
16376            Self::LiveSportsUpdated => "live_sports_updated",
16377            Self::TraderSynced => "trader_synced",
16378            Self::WhaleTraderSynced => "whale_trader_synced",
16379            Self::LargePositionsUpdated => "large_positions_updated",
16380            Self::WalletGradeChanged => "wallet_grade_changed",
16381            Self::SuspiciousTradeFlagged => "suspicious_trade_flagged",
16382            Self::InsiderRadarFlagRaised => "insider_radar_flag_raised",
16383            Self::SharpMoneyFlowDetected => "sharp_money_flow_detected",
16384            Self::SmartMoneyFlowDetected => "smart_money_flow_detected",
16385            Self::ExportJobReady => "export_job_ready",
16386            Self::ExportJobFailed => "export_job_failed",
16387            Self::ExportJobExpired => "export_job_expired",
16388            Self::ExportJobCancelled => "export_job_cancelled",
16389            Self::Other(value) => value,
16390        }
16391    }
16392}
16393
16394impl From<&str> for WebhookEventType {
16395    fn from(value: &str) -> Self {
16396        match value {
16397            "large_trade_inserted_v2" => Self::LargeTradeInsertedV2,
16398            "large_trades_inserted" => Self::LargeTradesInserted,
16399            "whale_trades_inserted" => Self::WhaleTradesInserted,
16400            "live_sports_updated" => Self::LiveSportsUpdated,
16401            "trader_synced" => Self::TraderSynced,
16402            "whale_trader_synced" => Self::WhaleTraderSynced,
16403            "large_positions_updated" => Self::LargePositionsUpdated,
16404            "wallet_grade_changed" => Self::WalletGradeChanged,
16405            "suspicious_trade_flagged" => Self::SuspiciousTradeFlagged,
16406            "insider_radar_flag_raised" => Self::InsiderRadarFlagRaised,
16407            "sharp_money_flow_detected" => Self::SharpMoneyFlowDetected,
16408            "smart_money_flow_detected" => Self::SmartMoneyFlowDetected,
16409            "export_job_ready" => Self::ExportJobReady,
16410            "export_job_failed" => Self::ExportJobFailed,
16411            "export_job_expired" => Self::ExportJobExpired,
16412            "export_job_cancelled" => Self::ExportJobCancelled,
16413            other => Self::Other(other.to_owned()),
16414        }
16415    }
16416}
16417
16418impl std::fmt::Display for WebhookEventType {
16419    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16420        f.write_str(self.as_str())
16421    }
16422}
16423
16424impl AsRef<str> for WebhookEventType {
16425    fn as_ref(&self) -> &str {
16426        self.as_str()
16427    }
16428}
16429
16430#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16431#[non_exhaustive]
16432pub struct WebhookRetryPolicy {
16433    pub max_attempts: i64,
16434    pub terminal_status: String,
16435    /// 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.
16436    pub retry_horizon_seconds: i64,
16437    /// 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.
16438    pub disable_after_consecutive_failures: i64,
16439}
16440
16441#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16442#[non_exhaustive]
16443pub struct WebhookSecretRotation {
16444    /// idle when no staged rotation exists, pending after prepare, and overlap after activate while both signing secrets are accepted.
16445    pub status: WebhookSecretRotationStatus,
16446    /// When the previous signing secret stops being emitted and accepted. null outside the overlap phase.
16447    #[serde(default)]
16448    pub overlap_expires_at: Option<String>,
16449}
16450
16451/// A value this release does not know is kept in `Other`, so a new value never fails a response.
16452#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
16453#[non_exhaustive]
16454pub enum WebhookSecretRotationStatus {
16455    /// `idle`
16456    #[serde(rename = "idle")]
16457    Idle,
16458    /// `pending`
16459    #[serde(rename = "pending")]
16460    Pending,
16461    /// `overlap`
16462    #[serde(rename = "overlap")]
16463    Overlap,
16464    /// A value this release does not know, kept as sent.
16465    #[serde(untagged)]
16466    Other(String),
16467}
16468
16469impl WebhookSecretRotationStatus {
16470    /// The value as the API spells it.
16471    pub fn as_str(&self) -> &str {
16472        match self {
16473            Self::Idle => "idle",
16474            Self::Pending => "pending",
16475            Self::Overlap => "overlap",
16476            Self::Other(value) => value,
16477        }
16478    }
16479}
16480
16481impl From<&str> for WebhookSecretRotationStatus {
16482    fn from(value: &str) -> Self {
16483        match value {
16484            "idle" => Self::Idle,
16485            "pending" => Self::Pending,
16486            "overlap" => Self::Overlap,
16487            other => Self::Other(other.to_owned()),
16488        }
16489    }
16490}
16491
16492impl std::fmt::Display for WebhookSecretRotationStatus {
16493    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16494        f.write_str(self.as_str())
16495    }
16496}
16497
16498impl AsRef<str> for WebhookSecretRotationStatus {
16499    fn as_ref(&self) -> &str {
16500        self.as_str()
16501    }
16502}
16503
16504/// A value this release does not know is kept in `Other`, so a new value never fails a response.
16505#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
16506#[non_exhaustive]
16507pub enum WebhookStatus {
16508    /// `pending_verification`
16509    #[serde(rename = "pending_verification")]
16510    PendingVerification,
16511    /// `active`
16512    #[serde(rename = "active")]
16513    Active,
16514    /// `disabled`
16515    #[serde(rename = "disabled")]
16516    Disabled,
16517    /// A value this release does not know, kept as sent.
16518    #[serde(untagged)]
16519    Other(String),
16520}
16521
16522impl WebhookStatus {
16523    /// The value as the API spells it.
16524    pub fn as_str(&self) -> &str {
16525        match self {
16526            Self::PendingVerification => "pending_verification",
16527            Self::Active => "active",
16528            Self::Disabled => "disabled",
16529            Self::Other(value) => value,
16530        }
16531    }
16532}
16533
16534impl From<&str> for WebhookStatus {
16535    fn from(value: &str) -> Self {
16536        match value {
16537            "pending_verification" => Self::PendingVerification,
16538            "active" => Self::Active,
16539            "disabled" => Self::Disabled,
16540            other => Self::Other(other.to_owned()),
16541        }
16542    }
16543}
16544
16545impl std::fmt::Display for WebhookStatus {
16546    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16547        f.write_str(self.as_str())
16548    }
16549}
16550
16551impl AsRef<str> for WebhookStatus {
16552    fn as_ref(&self) -> &str {
16553        self.as_str()
16554    }
16555}
16556
16557#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16558#[non_exhaustive]
16559pub struct WebhookVerification {
16560    /// 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.
16561    pub token: String,
16562    pub expires_at: String,
16563}
16564
16565#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16566#[non_exhaustive]
16567pub struct WebhookVerificationAttempt {
16568    pub id: String,
16569    pub object: String,
16570    pub webhook_id: i64,
16571    /// 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.
16572    pub state: WebhookVerificationAttemptState,
16573    /// Sanitized last observation. Null before an observation; queued retries may retain their previous failure outcome.
16574    #[serde(default)]
16575    pub outcome: Option<WebhookVerificationAttemptOutcome>,
16576    pub attempt_count: i64,
16577    pub max_attempts: i64,
16578    /// Earlier of the verification-token deadline and 15 minutes after admission. Activation is forbidden at or after this instant.
16579    pub expires_at: String,
16580    /// Scheduled retry/admission time while queued; null while running or terminal.
16581    #[serde(default)]
16582    pub next_attempt_at: Option<String>,
16583    /// Actual receiver HTTP status, when one arrived. No receiver response body or resolved address is returned.
16584    #[serde(default)]
16585    pub last_response_status: Option<i64>,
16586    #[serde(default)]
16587    pub started_at: Option<String>,
16588    #[serde(default)]
16589    pub completed_at: Option<String>,
16590    pub created_at: String,
16591    pub updated_at: String,
16592    /// Relative authorized API path for this attempt. Uses the same bearer credential as admission.
16593    pub status_url: String,
16594}
16595
16596/// A value this release does not know is kept in `Other`, so a new value never fails a response.
16597#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
16598#[non_exhaustive]
16599pub enum WebhookVerificationAttemptOutcome {
16600    /// `verified`
16601    #[serde(rename = "verified")]
16602    Verified,
16603    /// `target_rejected`
16604    #[serde(rename = "target_rejected")]
16605    TargetRejected,
16606    /// `challenge_timeout`
16607    #[serde(rename = "challenge_timeout")]
16608    ChallengeTimeout,
16609    /// `transport_failed`
16610    #[serde(rename = "transport_failed")]
16611    TransportFailed,
16612    /// `receiver_rejected`
16613    #[serde(rename = "receiver_rejected")]
16614    ReceiverRejected,
16615    /// `token_expired`
16616    #[serde(rename = "token_expired")]
16617    TokenExpired,
16618    /// `endpoint_changed`
16619    #[serde(rename = "endpoint_changed")]
16620    EndpointChanged,
16621    /// `owner_revoked`
16622    #[serde(rename = "owner_revoked")]
16623    OwnerRevoked,
16624    /// `attempts_exhausted`
16625    #[serde(rename = "attempts_exhausted")]
16626    AttemptsExhausted,
16627    /// `internal_error`
16628    #[serde(rename = "internal_error")]
16629    InternalError,
16630    /// A value this release does not know, kept as sent.
16631    #[serde(untagged)]
16632    Other(String),
16633}
16634
16635impl WebhookVerificationAttemptOutcome {
16636    /// The value as the API spells it.
16637    pub fn as_str(&self) -> &str {
16638        match self {
16639            Self::Verified => "verified",
16640            Self::TargetRejected => "target_rejected",
16641            Self::ChallengeTimeout => "challenge_timeout",
16642            Self::TransportFailed => "transport_failed",
16643            Self::ReceiverRejected => "receiver_rejected",
16644            Self::TokenExpired => "token_expired",
16645            Self::EndpointChanged => "endpoint_changed",
16646            Self::OwnerRevoked => "owner_revoked",
16647            Self::AttemptsExhausted => "attempts_exhausted",
16648            Self::InternalError => "internal_error",
16649            Self::Other(value) => value,
16650        }
16651    }
16652}
16653
16654impl From<&str> for WebhookVerificationAttemptOutcome {
16655    fn from(value: &str) -> Self {
16656        match value {
16657            "verified" => Self::Verified,
16658            "target_rejected" => Self::TargetRejected,
16659            "challenge_timeout" => Self::ChallengeTimeout,
16660            "transport_failed" => Self::TransportFailed,
16661            "receiver_rejected" => Self::ReceiverRejected,
16662            "token_expired" => Self::TokenExpired,
16663            "endpoint_changed" => Self::EndpointChanged,
16664            "owner_revoked" => Self::OwnerRevoked,
16665            "attempts_exhausted" => Self::AttemptsExhausted,
16666            "internal_error" => Self::InternalError,
16667            other => Self::Other(other.to_owned()),
16668        }
16669    }
16670}
16671
16672impl std::fmt::Display for WebhookVerificationAttemptOutcome {
16673    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16674        f.write_str(self.as_str())
16675    }
16676}
16677
16678impl AsRef<str> for WebhookVerificationAttemptOutcome {
16679    fn as_ref(&self) -> &str {
16680        self.as_str()
16681    }
16682}
16683
16684/// A value this release does not know is kept in `Other`, so a new value never fails a response.
16685#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
16686#[non_exhaustive]
16687pub enum WebhookVerificationAttemptState {
16688    /// `queued`
16689    #[serde(rename = "queued")]
16690    Queued,
16691    /// `running`
16692    #[serde(rename = "running")]
16693    Running,
16694    /// `verified`
16695    #[serde(rename = "verified")]
16696    Verified,
16697    /// `failed`
16698    #[serde(rename = "failed")]
16699    Failed,
16700    /// `cancelled`
16701    #[serde(rename = "cancelled")]
16702    Cancelled,
16703    /// `expired`
16704    #[serde(rename = "expired")]
16705    Expired,
16706    /// A value this release does not know, kept as sent.
16707    #[serde(untagged)]
16708    Other(String),
16709}
16710
16711impl WebhookVerificationAttemptState {
16712    /// The value as the API spells it.
16713    pub fn as_str(&self) -> &str {
16714        match self {
16715            Self::Queued => "queued",
16716            Self::Running => "running",
16717            Self::Verified => "verified",
16718            Self::Failed => "failed",
16719            Self::Cancelled => "cancelled",
16720            Self::Expired => "expired",
16721            Self::Other(value) => value,
16722        }
16723    }
16724}
16725
16726impl From<&str> for WebhookVerificationAttemptState {
16727    fn from(value: &str) -> Self {
16728        match value {
16729            "queued" => Self::Queued,
16730            "running" => Self::Running,
16731            "verified" => Self::Verified,
16732            "failed" => Self::Failed,
16733            "cancelled" => Self::Cancelled,
16734            "expired" => Self::Expired,
16735            other => Self::Other(other.to_owned()),
16736        }
16737    }
16738}
16739
16740impl std::fmt::Display for WebhookVerificationAttemptState {
16741    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16742        f.write_str(self.as_str())
16743    }
16744}
16745
16746impl AsRef<str> for WebhookVerificationAttemptState {
16747    fn as_ref(&self) -> &str {
16748        self.as_str()
16749    }
16750}
16751
16752#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16753#[non_exhaustive]
16754pub struct WhaleDatasetArtifactManifest {
16755    /// Version of the artifact manifest contract.
16756    pub manifest_version: String,
16757    pub format: String,
16758    pub schema_version: String,
16759    pub coverage: String,
16760    pub generation: WhaleDatasetGeneration,
16761    /// Number of trade rows written.
16762    pub row_count: i64,
16763    /// Exact byte count of the decompressed content stream clients receive.
16764    pub content_size_bytes: i64,
16765    /// Lowercase SHA-256 of the decompressed content bytes.
16766    pub content_sha256: String,
16767    /// Exact byte count of the gzip-compressed bytes stored by the object provider.
16768    pub compressed_size_bytes: i64,
16769    /// Lowercase SHA-256 of the stored gzip bytes; the multipart ETag is not used as this checksum.
16770    pub compressed_sha256: String,
16771}
16772
16773#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16774#[non_exhaustive]
16775pub struct WhaleDatasetContinuation {
16776    pub path: String,
16777    /// Opaque commit-safe replay cursor; replay the same condition_id and min_size.
16778    pub cursor: String,
16779    /// Writer floor included by the replay cursor. It can precede the snapshot horizon to include arrivals after the finite window end.
16780    pub from_commit_xid: String,
16781    #[serde(default)]
16782    pub condition_id: Option<String>,
16783    /// Normalized USD threshold; pass it to the replay query.
16784    #[serde(default)]
16785    pub min_size: Option<String>,
16786    pub deduplication_identity: String,
16787    pub time_window_applies_to_deltas: bool,
16788    pub delivery: String,
16789}
16790
16791/// Normalized immutable request; [from, to), maximum 31 days; min_size rounded to cents like durable replay.
16792#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16793#[non_exhaustive]
16794pub struct WhaleDatasetFilters {
16795    pub from: String,
16796    pub to: String,
16797    #[serde(default)]
16798    pub condition_id: Option<String>,
16799    #[serde(default)]
16800    pub min_size_cents: Option<i64>,
16801}
16802
16803#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16804#[non_exhaustive]
16805pub struct WhaleDatasetGeneration {
16806    pub dataset_schema_version: String,
16807    pub id: String,
16808    pub selected_at: String,
16809    pub consistency: String,
16810    pub filters: WhaleDatasetFilters,
16811    /// All snapshot rows have a writer xid strictly below this closed visibility horizon. Decimal string preserves integer precision.
16812    pub commit_horizon_xid: String,
16813    pub continuation: WhaleDatasetContinuation,
16814    pub source: String,
16815    /// Best-effort detected whale alerts only; not all provider fills. No trader or market enrichment.
16816    pub coverage: String,
16817    pub expires_at: String,
16818    pub extraction_elapsed_ms: i64,
16819}
16820
16821#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16822#[non_exhaustive]
16823pub struct WhaleDatasetJob {
16824    pub object: String,
16825    pub data: WhaleDatasetJobData,
16826    pub meta: ResponseMeta,
16827}
16828
16829#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16830#[non_exhaustive]
16831pub struct WhaleDatasetJobData {
16832    pub job_id: i64,
16833    /// 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.
16834    pub status: TraderExportJobDataStatus,
16835    pub format: String,
16836    #[serde(default)]
16837    pub total_trades: Option<i64>,
16838    #[serde(default)]
16839    pub processed_trades: Option<i64>,
16840    #[serde(default)]
16841    pub file_size: Option<i64>,
16842    #[serde(default)]
16843    pub error: Option<String>,
16844    /// True when status never changes again (ready, failed, expired, cancelled). Stop polling.
16845    pub terminal: bool,
16846    /// 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.
16847    pub next_action: NextAction,
16848    /// 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.
16849    #[serde(default, skip_serializing_if = "Option::is_none")]
16850    pub poll_after_s: Option<i64>,
16851    pub created_at: String,
16852    /// When the worker last claimed the job; null while queued.
16853    #[serde(default)]
16854    pub started_at: Option<String>,
16855    /// When the file became downloadable. null before ready, and on jobs finalized before this field existed.
16856    #[serde(default)]
16857    pub ready_at: Option<String>,
16858    #[serde(default)]
16859    pub failed_at: Option<String>,
16860    /// 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.
16861    pub expires_at: String,
16862    /// When the job became expired; null until then.
16863    #[serde(default)]
16864    pub expired_at: Option<String>,
16865    /// Snapshot selection clock, null until the artifact is written; not provider completeness.
16866    #[serde(default)]
16867    pub data_as_of: Option<String>,
16868    /// 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.
16869    #[serde(default)]
16870    pub cancel_requested_at: Option<String>,
16871    /// When the job reached cancelled; null until then.
16872    #[serde(default)]
16873    pub cancelled_at: Option<String>,
16874    /// 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.
16875    pub attempt: i64,
16876    /// The job fails when attempt reaches this.
16877    pub max_attempts: i64,
16878    /// Present only while status is ready: the stored object's identity, so a client can check the download it receives.
16879    #[serde(default, skip_serializing_if = "Option::is_none")]
16880    pub artifact: Option<WhaleDatasetJobDataArtifact>,
16881    pub filters: WhaleDatasetFilters,
16882}
16883
16884/// Present only while status is ready: the stored object's identity, so a client can check the download it receives.
16885#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16886#[non_exhaustive]
16887pub struct WhaleDatasetJobDataArtifact {
16888    /// Stable identity for this completed export artifact; unchanged when a temporary download URL is renewed.
16889    pub artifact_id: String,
16890    /// The storage ETag of the object.
16891    #[serde(default)]
16892    pub etag: Option<String>,
16893    /// Bytes on the wire (gzip); file_size is the decompressed size.
16894    #[serde(default)]
16895    pub compressed_size_bytes: Option<i64>,
16896    pub content_type: String,
16897    pub content_encoding: String,
16898    /// Immutable source, window, replay handoff, count and hashes of both content and gzip bytes.
16899    #[serde(default)]
16900    pub manifest: Option<WhaleDatasetArtifactManifest>,
16901}
16902
16903#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16904#[non_exhaustive]
16905pub struct WhaleDatasetTrade {
16906    /// wt_<whale_alert_id>; deduplication identity shared with expanded replay.
16907    pub id: String,
16908    /// Decimal whale-alert ID.
16909    pub sequence: String,
16910    /// trd_<local trader ID>.
16911    pub trader_id: String,
16912    pub condition_id: String,
16913    pub platform: String,
16914    pub traded_at: String,
16915    pub side: Side,
16916    /// Provider outcome index, null before the canonical outcome trust boundary.
16917    #[serde(default)]
16918    pub outcome_index: Option<i64>,
16919    /// Exact stored NUMERIC price; decimal string.
16920    pub price: String,
16921    /// Exact stored NUMERIC USD notional; decimal string.
16922    pub size_usd: String,
16923    /// Writer transaction ID, decimal string.
16924    pub inserted_xid: String,
16925    /// Stored source trade identity.
16926    pub trade_event_id: String,
16927    #[serde(default)]
16928    pub source_trade_ingested_at: Option<String>,
16929}
16930
16931/// A value this release does not know is kept in `Other`, so a new value never fails a response.
16932#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
16933#[non_exhaustive]
16934pub enum Window {
16935    /// `24h`
16936    #[serde(rename = "24h")]
16937    V24h,
16938    /// `7d`
16939    #[serde(rename = "7d")]
16940    V7d,
16941    /// `all`
16942    #[serde(rename = "all")]
16943    All,
16944    /// A value this release does not know, kept as sent.
16945    #[serde(untagged)]
16946    Other(String),
16947}
16948
16949impl Window {
16950    /// The value as the API spells it.
16951    pub fn as_str(&self) -> &str {
16952        match self {
16953            Self::V24h => "24h",
16954            Self::V7d => "7d",
16955            Self::All => "all",
16956            Self::Other(value) => value,
16957        }
16958    }
16959}
16960
16961impl From<&str> for Window {
16962    fn from(value: &str) -> Self {
16963        match value {
16964            "24h" => Self::V24h,
16965            "7d" => Self::V7d,
16966            "all" => Self::All,
16967            other => Self::Other(other.to_owned()),
16968        }
16969    }
16970}
16971
16972impl std::fmt::Display for Window {
16973    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16974        f.write_str(self.as_str())
16975    }
16976}
16977
16978impl AsRef<str> for Window {
16979    fn as_ref(&self) -> &str {
16980        self.as_str()
16981    }
16982}
16983
16984/// A value this release does not know is kept in `Other`, so a new value never fails a response.
16985#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
16986#[non_exhaustive]
16987pub enum WithdrawalReason {
16988    /// `provider_game_cancelled`
16989    #[serde(rename = "provider_game_cancelled")]
16990    ProviderGameCancelled,
16991    /// `published_after_kickoff`
16992    #[serde(rename = "published_after_kickoff")]
16993    PublishedAfterKickoff,
16994    /// A value this release does not know, kept as sent.
16995    #[serde(untagged)]
16996    Other(String),
16997}
16998
16999impl WithdrawalReason {
17000    /// The value as the API spells it.
17001    pub fn as_str(&self) -> &str {
17002        match self {
17003            Self::ProviderGameCancelled => "provider_game_cancelled",
17004            Self::PublishedAfterKickoff => "published_after_kickoff",
17005            Self::Other(value) => value,
17006        }
17007    }
17008}
17009
17010impl From<&str> for WithdrawalReason {
17011    fn from(value: &str) -> Self {
17012        match value {
17013            "provider_game_cancelled" => Self::ProviderGameCancelled,
17014            "published_after_kickoff" => Self::PublishedAfterKickoff,
17015            other => Self::Other(other.to_owned()),
17016        }
17017    }
17018}
17019
17020impl std::fmt::Display for WithdrawalReason {
17021    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17022        f.write_str(self.as_str())
17023    }
17024}
17025
17026impl AsRef<str> for WithdrawalReason {
17027    fn as_ref(&self) -> &str {
17028        self.as_str()
17029    }
17030}