getanyapi 0.72.0__tar.gz → 0.73.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. {getanyapi-0.72.0 → getanyapi-0.73.0}/PKG-INFO +1 -1
  2. {getanyapi-0.72.0 → getanyapi-0.73.0}/pyproject.toml +1 -1
  3. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/__init__.py +1 -1
  4. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/alibaba.py +2 -2
  5. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/capterra.py +1 -1
  6. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/facebook.py +22 -9
  7. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/google_ads.py +8 -2
  8. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/google_shopping.py +2 -2
  9. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/instagram.py +20 -9
  10. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/linkedin.py +12 -6
  11. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/reddit.py +5 -2
  12. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/threads.py +4 -1
  13. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/tiktok.py +9 -3
  14. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/tiktok_shop.py +28 -9
  15. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/tripadvisor.py +3 -3
  16. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/twitter.py +8 -2
  17. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/youtube.py +21 -7
  18. {getanyapi-0.72.0 → getanyapi-0.73.0}/.gitignore +0 -0
  19. {getanyapi-0.72.0 → getanyapi-0.73.0}/README.md +0 -0
  20. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/_account.py +0 -0
  21. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/_async_client.py +0 -0
  22. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/_client.py +0 -0
  23. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/_errors.py +0 -0
  24. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/_idempotency.py +0 -0
  25. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/_pagination.py +0 -0
  26. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/_transport.py +0 -0
  27. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/discovery_types.py +0 -0
  28. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/__init__.py +0 -0
  29. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/ahrefs.py +0 -0
  30. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/airbnb.py +0 -0
  31. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/amazon.py +0 -0
  32. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/apollo.py +0 -0
  33. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/appstore.py +0 -0
  34. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/bluesky.py +0 -0
  35. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/booking.py +0 -0
  36. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/chatgpt.py +0 -0
  37. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/coinmarketcap.py +0 -0
  38. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/company.py +0 -0
  39. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/company_enrichment.py +0 -0
  40. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/company_identify.py +0 -0
  41. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/company_search.py +0 -0
  42. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/congress.py +0 -0
  43. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/contact_enrichment.py +0 -0
  44. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/douyin.py +0 -0
  45. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/ebay.py +0 -0
  46. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/email.py +0 -0
  47. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/email_finding.py +0 -0
  48. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/email_verification.py +0 -0
  49. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/fiverr.py +0 -0
  50. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/g2.py +0 -0
  51. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/gemini.py +0 -0
  52. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/github.py +0 -0
  53. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/glassdoor.py +0 -0
  54. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/google.py +0 -0
  55. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/google_finance.py +0 -0
  56. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/hackernews.py +0 -0
  57. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/indeed.py +0 -0
  58. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/job_search.py +0 -0
  59. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/maps.py +0 -0
  60. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/mobile_phone.py +0 -0
  61. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/naver.py +0 -0
  62. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/nextdoor.py +0 -0
  63. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/people_search.py +0 -0
  64. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/perplexity.py +0 -0
  65. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/person.py +0 -0
  66. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/person_enrichment.py +0 -0
  67. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/pinterest.py +0 -0
  68. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/playstore.py +0 -0
  69. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/polymarket.py +0 -0
  70. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/property_records.py +0 -0
  71. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/realtor.py +0 -0
  72. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/redfin.py +0 -0
  73. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/rednote.py +0 -0
  74. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/sec.py +0 -0
  75. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/semrush.py +0 -0
  76. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/seo.py +0 -0
  77. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/similarweb.py +0 -0
  78. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/snapchat.py +0 -0
  79. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/social.py +0 -0
  80. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/spotify.py +0 -0
  81. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/substack.py +0 -0
  82. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/technographics.py +0 -0
  83. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/trustpilot.py +0 -0
  84. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/truthsocial.py +0 -0
  85. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/upwork.py +0 -0
  86. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/walmart.py +0 -0
  87. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/web.py +0 -0
  88. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/weibo.py +0 -0
  89. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/yahoo_finance.py +0 -0
  90. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/yelp.py +0 -0
  91. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/zhihu.py +0 -0
  92. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/platforms/zillow.py +0 -0
  93. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/py.typed +0 -0
  94. {getanyapi-0.72.0 → getanyapi-0.73.0}/src/getanyapi/types.py +0 -0
  95. {getanyapi-0.72.0 → getanyapi-0.73.0}/tests/conftest.py +0 -0
  96. {getanyapi-0.72.0 → getanyapi-0.73.0}/tests/test_account.py +0 -0
  97. {getanyapi-0.72.0 → getanyapi-0.73.0}/tests/test_client.py +0 -0
  98. {getanyapi-0.72.0 → getanyapi-0.73.0}/tests/test_durable_requests.py +0 -0
  99. {getanyapi-0.72.0 → getanyapi-0.73.0}/tests/test_envelope.py +0 -0
  100. {getanyapi-0.72.0 → getanyapi-0.73.0}/tests/test_errors.py +0 -0
  101. {getanyapi-0.72.0 → getanyapi-0.73.0}/tests/test_fixture_roundtrip.py +0 -0
  102. {getanyapi-0.72.0 → getanyapi-0.73.0}/tests/test_fixture_sweep.py +0 -0
  103. {getanyapi-0.72.0 → getanyapi-0.73.0}/tests/test_not_found_reason.py +0 -0
  104. {getanyapi-0.72.0 → getanyapi-0.73.0}/tests/test_pagination.py +0 -0
  105. {getanyapi-0.72.0 → getanyapi-0.73.0}/tests/test_transport.py +0 -0
  106. {getanyapi-0.72.0 → getanyapi-0.73.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: getanyapi
3
- Version: 0.72.0
3
+ Version: 0.73.0
4
4
  Summary: Official typed Python SDK for AnyAPI: any API, one wallet, USD, no subscriptions.
5
5
  Project-URL: Homepage, https://getanyapi.com
6
6
  Project-URL: Documentation, https://getanyapi.com/docs
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "getanyapi"
7
- version = "0.72.0"
7
+ version = "0.73.0"
8
8
  description = "Official typed Python SDK for AnyAPI: any API, one wallet, USD, no subscriptions."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -55,7 +55,7 @@ from .types import (
55
55
  unwrap,
56
56
  )
57
57
 
58
- __version__ = "0.72.0"
58
+ __version__ = "0.73.0"
59
59
 
60
60
  __all__ = [
61
61
  # clients + top-level functions
@@ -84,12 +84,12 @@ class AlibabaSearchItem(BaseModel):
84
84
  )
85
85
  rating: float | None = Field(
86
86
  default=None,
87
- description="Average buyer review score, 0-5; 0 when the listing has no reviews.",
87
+ description="Average buyer review score, 0-5; null when Alibaba shows no review score for the supplier.",
88
88
  )
89
89
  review_count: int | None = Field(
90
90
  default=None,
91
91
  alias="reviewCount",
92
- description="Number of buyer reviews; 0 when none.",
92
+ description="Number of buyer reviews; null when Alibaba shows no review count for the supplier.",
93
93
  )
94
94
  supplier_name: str | None = Field(
95
95
  default=None, alias="supplierName", description="Supplier / company name."
@@ -110,7 +110,7 @@ class CapterraReviewsItem(BaseModel):
110
110
  )
111
111
  incentivized: bool | None = Field(
112
112
  default=None,
113
- description="Whether the reviewer received an incentive for the review. Populated whenever the provider has data for the entity. Present whenever the upstream returns this record.",
113
+ description="Whether the reviewer received an incentive for the review (for example a nominal gift); null when the source does not say. Populated whenever the provider has data for the entity. Present whenever the upstream returns this record.",
114
114
  )
115
115
  owner_response: str | None = Field(
116
116
  default=None,
@@ -378,6 +378,8 @@ class FacebookPhotosInput(TypedDict, total=False):
378
378
  """Optional. Source ids to skip for this request, taken from this endpoint's `lanes[].source.id`. The cheapest remaining source serves and the price is that of the dearest remaining source. An id that does not serve this endpoint, or that is also in `source`, is rejected as invalid input with no charge; skipping every source is rejected the same way."""
379
379
  preferLatencyUnderMs: NotRequired[int]
380
380
  """Optional; omit it and routing is unchanged, with the cheapest source serving. Prefer sources whose typical response time (median over the trailing 30 days, as published on this endpoint's lane health) is under this many milliseconds; among those, the cheapest serves. This can raise your price: when the cheapest source misses the target, a faster and dearer one serves, and you are quoted and charged its price. If no source is that fast the request is still served, by whichever source offers the best speed for its price - it is never refused for being slow. Sources we have not timed are tried last. This is a preference, not a guarantee: the median describes past requests and is not a ceiling on this one, and it excludes any wait this request itself asks for. On a paginated walk it applies to the first page only: later pages stay with the source that page chose, at the price it was quoted. Minimum: 1."""
381
+ requireFields: NotRequired[list[Literal["imageHeight", "imageWidth", "nextPageId"]]]
382
+ """Optional; omit it and routing is unchanged, with the cheapest source serving. Name the output fields this request must be able to return, for example `imageWidth`, and it is served only by a source that returns every one of them. Fields you do not name are still returned whenever the serving source has them. This can raise your price: when the cheapest source cannot return a named field, a dearer source serves, and you are quoted and charged its price. A named field can still be absent on a photo that genuinely lacks it. Naming a combination that no single source returns together is refused as invalid input, with no charge."""
381
383
  source: NotRequired[list[str]]
382
384
  """Optional. Source ids to prefer, in order, taken from this endpoint's `lanes[].source.id` in /catalog or /apis. Omit it and the cheapest source serves, with automatic failover. Listed sources are tried first in the order given, then the others, unless `allowFallbacks` is false. A single source with `allowFallbacks` false is served only by that source at its price, quoted and charged exactly, with no failover. The price is that of the dearest source that may serve. An id that does not serve this endpoint is rejected as invalid input with no charge; a listed source that is not serving right now is refused with no charge, so omit `source` to be served by another. On a paginated walk, later pages must include the source that served page one, or omit `source`."""
383
385
  url: Required[str]
@@ -904,8 +906,9 @@ class FacebookAdsSearchAd(BaseModel):
904
906
  model_config = ConfigDict(extra="allow", populate_by_name=True)
905
907
 
906
908
  active: bool
907
- ad_count: int = Field(
908
- alias="adCount", description="Number of ads in this campaign (collation count)."
909
+ ad_count: int | None = Field(
910
+ alias="adCount",
911
+ description="Number of ads in this campaign (collation count). Null when the source does not report it.",
909
912
  )
910
913
  caption: str | None = Field(
911
914
  default=None,
@@ -1098,8 +1101,9 @@ class FacebookCompanyAdsAd(BaseModel):
1098
1101
  model_config = ConfigDict(extra="allow", populate_by_name=True)
1099
1102
 
1100
1103
  active: bool
1101
- ad_count: int = Field(
1102
- alias="adCount", description="Number of ads in this campaign (collation count)."
1104
+ ad_count: int | None = Field(
1105
+ alias="adCount",
1106
+ description="Number of ads in this campaign (collation count). Null when the source does not report it.",
1103
1107
  )
1104
1108
  caption: str | None = Field(
1105
1109
  default=None,
@@ -1578,7 +1582,7 @@ class FacebookMarketplaceListing(BaseModel):
1578
1582
  created_utc: float | None = Field(
1579
1583
  default=None,
1580
1584
  alias="createdUtc",
1581
- description="UTC epoch timestamp in seconds (Unix time) the listing was created. Multiply by 1000 for a JS Date in milliseconds.",
1585
+ description="UTC epoch timestamp in seconds (Unix time) the listing was created. Multiply by 1000 for a JS Date in milliseconds. Null when the source does not report it.",
1582
1586
  )
1583
1587
  delivery_types: list[str] | None = Field(
1584
1588
  default=None,
@@ -1911,7 +1915,10 @@ class FacebookPhotosData(BaseModel):
1911
1915
  alias="nextCursor",
1912
1916
  description="Opaque cursor for the next page of photos, or null when this lane has no more. Pass it back as cursor to continue.",
1913
1917
  )
1914
- next_page_id: str = Field(alias="nextPageId")
1918
+ next_page_id: str | None = Field(
1919
+ alias="nextPageId",
1920
+ description="Facebook's own id for the next page of photos. Null when the serving source does not report it; pass nextCursor back as cursor to continue either way.",
1921
+ )
1915
1922
  photos: list[FacebookPhotosPhoto] = Field(
1916
1923
  description="Populated whenever the provider has data for the entity."
1917
1924
  )
@@ -1926,12 +1933,18 @@ class FacebookPhotosPhoto(BaseModel):
1926
1933
  id: str = Field(
1927
1934
  description="Populated whenever the provider has data for the entity."
1928
1935
  )
1929
- image_height: int = Field(alias="imageHeight")
1936
+ image_height: int | None = Field(
1937
+ alias="imageHeight",
1938
+ description="Height of imageUrl in pixels. Null when the serving source does not report it.",
1939
+ )
1930
1940
  image_url: str = Field(
1931
1941
  alias="imageUrl",
1932
1942
  description="Populated whenever the provider has data for the entity.",
1933
1943
  )
1934
- image_width: int = Field(alias="imageWidth")
1944
+ image_width: int | None = Field(
1945
+ alias="imageWidth",
1946
+ description="Width of imageUrl in pixels. Null when the serving source does not report it.",
1947
+ )
1935
1948
  photo_id: str = Field(
1936
1949
  alias="photoId",
1937
1950
  description="Populated whenever the provider has data for the entity.",
@@ -2436,7 +2449,7 @@ class FacebookSearchPostsData(BaseModel):
2436
2449
  images_count: int | None = Field(
2437
2450
  default=None,
2438
2451
  alias="imagesCount",
2439
- description="Number of images attached to the post.",
2452
+ description="Number of images attached to the post. Null when the source does not report it.",
2440
2453
  )
2441
2454
  items: list[FacebookSearchPostsItem] = Field(
2442
2455
  description="Matching public Facebook post records for the query. Populated whenever the provider has data for the entity."
@@ -120,8 +120,14 @@ class GoogleAdsAdDetailsData(BaseModel):
120
120
  format: str = Field(
121
121
  description="Populated whenever the provider has data for the entity."
122
122
  )
123
- impressions_max: int = Field(alias="impressionsMax")
124
- impressions_min: int = Field(alias="impressionsMin")
123
+ impressions_max: int | None = Field(
124
+ alias="impressionsMax",
125
+ description="Upper bound of the impressions range. Null when Google does not publish one for this creative.",
126
+ )
127
+ impressions_min: int | None = Field(
128
+ alias="impressionsMin",
129
+ description="Lower bound of the impressions range. Null when Google does not publish one for this creative.",
130
+ )
125
131
  last_shown: str = Field(alias="lastShown", description="ISO 8601 date.")
126
132
  url: str | None = Field(
127
133
  default=None, description="Google Ads Transparency Center URL for the creative."
@@ -98,12 +98,12 @@ class GoogleShoppingSearchItem(BaseModel):
98
98
  default=None, alias="productId", description="Provider product identifier."
99
99
  )
100
100
  rating: float | None = Field(
101
- default=None, description="Average product rating, 0-5; 0 when unrated."
101
+ default=None, description="Average product rating, 0-5; null when unrated."
102
102
  )
103
103
  reviews_count: int | None = Field(
104
104
  default=None,
105
105
  alias="reviewsCount",
106
- description="Number of ratings / reviews; 0 when none reported.",
106
+ description="Number of ratings / reviews; null when none reported.",
107
107
  )
108
108
  seller: str | None = Field(
109
109
  default=None,
@@ -306,7 +306,7 @@ class InstagramProfileInput(TypedDict, total=False):
306
306
  """Optional. Source ids to skip for this request, taken from this endpoint's `lanes[].source.id`. The cheapest remaining source serves and the price is that of the dearest remaining source. An id that does not serve this endpoint, or that is also in `source`, is rejected as invalid input with no charge; skipping every source is rejected the same way."""
307
307
  preferLatencyUnderMs: NotRequired[int]
308
308
  """Optional; omit it and routing is unchanged, with the cheapest source serving. Prefer sources whose typical response time (median over the trailing 30 days, as published on this endpoint's lane health) is under this many milliseconds; among those, the cheapest serves. This can raise your price: when the cheapest source misses the target, a faster and dearer one serves, and you are quoted and charged its price. If no source is that fast the request is still served, by whichever source offers the best speed for its price - it is never refused for being slow. Sources we have not timed are tried last. This is a preference, not a guarantee: the median describes past requests and is not a ceiling on this one, and it excludes any wait this request itself asks for. On a paginated walk it applies to the first page only: later pages stay with the source that page chose, at the price it was quoted. Minimum: 1."""
309
- requireFields: NotRequired[list[Literal["contactMethod"]]]
309
+ requireFields: NotRequired[list[Literal["contactMethod", "posts"]]]
310
310
  """Optional; omit it and routing is unchanged, with the cheapest source serving. Name the output fields this request must be able to return, for example `contactMethod`, and it is served only by a source that returns every one of them. Fields you do not name are still returned whenever the serving source has them. This can raise your price: when the cheapest source cannot return a named field, a dearer source serves, and you are quoted and charged its price. A named field can still be absent on a profile that genuinely lacks it. Naming a combination that no single source returns together is refused as invalid input, with no charge."""
311
311
  source: NotRequired[list[str]]
312
312
  """Optional. Source ids to prefer, in order, taken from this endpoint's `lanes[].source.id` in /catalog or /apis. Omit it and the cheapest source serves, with automatic failover. Listed sources are tried first in the order given, then the others, unless `allowFallbacks` is false. A single source with `allowFallbacks` false is served only by that source at its price, quoted and charged exactly, with no failover. The price is that of the dearest source that may serve. An id that does not serve this endpoint is rejected as invalid input with no charge; a listed source that is not serving right now is refused with no charge, so omit `source` to be served by another. On a paginated walk, later pages must include the source that served page one, or omit `source`."""
@@ -467,6 +467,8 @@ class InstagramSearchProfilesInput(TypedDict, total=False):
467
467
  """Optional; omit it and routing is unchanged, with the cheapest source serving. Prefer sources whose typical response time (median over the trailing 30 days, as published on this endpoint's lane health) is under this many milliseconds; among those, the cheapest serves. This can raise your price: when the cheapest source misses the target, a faster and dearer one serves, and you are quoted and charged its price. If no source is that fast the request is still served, by whichever source offers the best speed for its price - it is never refused for being slow. Sources we have not timed are tried last. This is a preference, not a guarantee: the median describes past requests and is not a ceiling on this one, and it excludes any wait this request itself asks for. On a paginated walk it applies to the first page only: later pages stay with the source that page chose, at the price it was quoted. Minimum: 1."""
468
468
  query: Required[str]
469
469
  """Bio or caption keyword/phrase to search for."""
470
+ requireFields: NotRequired[list[Literal["private"]]]
471
+ """Optional; omit it and routing is unchanged, with the cheapest source serving. Name the output fields this request must be able to return, for example `private`, and it is served only by a source that returns every one of them. Fields you do not name are still returned whenever the serving source has them. This can raise your price: when the cheapest source cannot return a named field, a dearer source serves, and you are quoted and charged its price. A named field can still be absent on a profile that genuinely lacks it. Naming a combination that no single source returns together is refused as invalid input, with no charge."""
470
472
  source: NotRequired[list[str]]
471
473
  """Optional. Source ids to prefer, in order, taken from this endpoint's `lanes[].source.id` in /catalog or /apis. Omit it and the cheapest source serves, with automatic failover. Listed sources are tried first in the order given, then the others, unless `allowFallbacks` is false. A single source with `allowFallbacks` false is served only by that source at its price, quoted and charged exactly, with no failover. The price is that of the dearest source that may serve. An id that does not serve this endpoint is rejected as invalid input with no charge; a listed source that is not serving right now is refused with no charge, so omit `source` to be served by another. On a paginated walk, later pages must include the source that served page one, or omit `source`."""
472
474
 
@@ -1466,7 +1468,9 @@ class InstagramPostCommentsComment(BaseModel):
1466
1468
  id: str = Field(
1467
1469
  description="Populated whenever the provider has data for the entity."
1468
1470
  )
1469
- likes: int
1471
+ likes: int | None = Field(
1472
+ description="Number of likes on the comment. Null when the source does not report it."
1473
+ )
1470
1474
  text: str = Field(
1471
1475
  description="Populated whenever the provider has data for the entity."
1472
1476
  )
@@ -1553,8 +1557,8 @@ class InstagramProfileData(BaseModel):
1553
1557
  alias="isBusiness",
1554
1558
  description="Whether Instagram flags the account as a business account.",
1555
1559
  )
1556
- posts: int = Field(
1557
- description="Always 0: none of the sources behind this API returns the account's total post count."
1560
+ posts: int | None = Field(
1561
+ description="Total number of posts on the account. Null when the serving source does not report it."
1558
1562
  )
1559
1563
  private: bool = Field(description="Whether the account is private.")
1560
1564
  user_id: str | None = Field(
@@ -2080,7 +2084,9 @@ class InstagramSearchProfilesProfile(BaseModel):
2080
2084
  description="Populated whenever the provider has data for the entity."
2081
2085
  )
2082
2086
  posts: int
2083
- private: bool
2087
+ private: bool | None = Field(
2088
+ description="Whether the account is private. Null when the serving source does not report it."
2089
+ )
2084
2090
  url: str | None = Field(default=None, description="Canonical URL of the profile.")
2085
2091
  verified: bool
2086
2092
 
@@ -2161,7 +2167,9 @@ class InstagramSimilarProfilesProfile(BaseModel):
2161
2167
  description="Profile picture URL, as Instagram's CDN serves it.",
2162
2168
  )
2163
2169
  display_name: str = Field(alias="displayName", description="Account display name.")
2164
- private: bool = Field(description="Whether the account is private.")
2170
+ private: bool | None = Field(
2171
+ description="Whether the account is private. Null when the source does not report it."
2172
+ )
2165
2173
  user_id: str = Field(
2166
2174
  alias="userId", description="Instagram's numeric account id, as a string."
2167
2175
  )
@@ -2337,7 +2345,9 @@ class InstagramTaggedPostsPost(BaseModel):
2337
2345
  id: str = Field(
2338
2346
  description="The post's numeric Instagram media ID, as a string. Populated whenever the provider has data for the entity."
2339
2347
  )
2340
- likes: int = Field(description="Number of likes on the post.")
2348
+ likes: int | None = Field(
2349
+ description="Number of likes on the post. Null when the source does not report it, including when the owner hides like counts."
2350
+ )
2341
2351
  url: str = Field(
2342
2352
  description="Canonical URL of the post, with tracking query params stripped. Populated whenever the provider has data for the entity."
2343
2353
  )
@@ -2810,8 +2820,9 @@ class InstagramWebReelsSearchReel(BaseModel):
2810
2820
  alias="createdUtc",
2811
2821
  description="UTC epoch timestamp in seconds (Unix time). Multiply by 1000 for a JS Date in milliseconds.",
2812
2822
  )
2813
- duration_seconds: float = Field(
2814
- alias="durationSeconds", description="Reel duration in seconds."
2823
+ duration_seconds: float | None = Field(
2824
+ alias="durationSeconds",
2825
+ description="Reel duration in seconds. Null when the source does not report it.",
2815
2826
  )
2816
2827
  likes: int = Field(description="Number of likes on the reel.")
2817
2828
  paid_partnership: bool = Field(
@@ -1281,10 +1281,12 @@ class LinkedinCompanyEmployeeCountRange(BaseModel):
1281
1281
  model_config = ConfigDict(extra="allow")
1282
1282
 
1283
1283
  end: int | None = Field(
1284
- default=None, description="Upper bound of the employee-count bucket."
1284
+ default=None,
1285
+ description="Upper bound of the employee-count bucket; null when the source does not report it.",
1285
1286
  )
1286
1287
  start: int | None = Field(
1287
- default=None, description="Lower bound of the employee-count bucket."
1288
+ default=None,
1289
+ description="Lower bound of the employee-count bucket; null when the source does not report it.",
1288
1290
  )
1289
1291
 
1290
1292
 
@@ -1310,7 +1312,7 @@ class LinkedinCompanyFundingData(BaseModel):
1310
1312
  num_funding_rounds: int | None = Field(
1311
1313
  default=None,
1312
1314
  alias="numFundingRounds",
1313
- description="Total number of funding rounds.",
1315
+ description="Total number of funding rounds; null when the source does not report it.",
1314
1316
  )
1315
1317
 
1316
1318
 
@@ -2051,8 +2053,12 @@ class LinkedinJobsCompany(BaseModel):
2051
2053
  class LinkedinJobsSalary(BaseModel):
2052
2054
  model_config = ConfigDict(extra="allow")
2053
2055
 
2054
- max: float | None = Field(default=None, description="Maximum salary.")
2055
- min: float | None = Field(default=None, description="Minimum salary.")
2056
+ max: float | None = Field(
2057
+ default=None, description="Maximum salary; null when the posting shows none."
2058
+ )
2059
+ min: float | None = Field(
2060
+ default=None, description="Minimum salary; null when the posting shows none."
2061
+ )
2056
2062
  text: str | None = Field(
2057
2063
  default=None, description="Salary as displayed (e.g. '300,000 - 330,000 USD')."
2058
2064
  )
@@ -3948,7 +3954,7 @@ class LinkedinSearchProfilesEmailItem(BaseModel):
3948
3954
  follower_count: int | None = Field(
3949
3955
  default=None,
3950
3956
  alias="followerCount",
3951
- description="Number of followers of the profile.",
3957
+ description="Number of followers of the profile; null when the source does not report it.",
3952
3958
  )
3953
3959
  handle: str | None = Field(
3954
3960
  default=None,
@@ -94,6 +94,8 @@ class RedditProfileInput(TypedDict, total=False):
94
94
  """Optional. Source ids to skip for this request, taken from this endpoint's `lanes[].source.id`. The cheapest remaining source serves and the price is that of the dearest remaining source. An id that does not serve this endpoint, or that is also in `source`, is rejected as invalid input with no charge; skipping every source is rejected the same way."""
95
95
  preferLatencyUnderMs: NotRequired[int]
96
96
  """Optional; omit it and routing is unchanged, with the cheapest source serving. Prefer sources whose typical response time (median over the trailing 30 days, as published on this endpoint's lane health) is under this many milliseconds; among those, the cheapest serves. This can raise your price: when the cheapest source misses the target, a faster and dearer one serves, and you are quoted and charged its price. If no source is that fast the request is still served, by whichever source offers the best speed for its price - it is never refused for being slow. Sources we have not timed are tried last. This is a preference, not a guarantee: the median describes past requests and is not a ceiling on this one, and it excludes any wait this request itself asks for. On a paginated walk it applies to the first page only: later pages stay with the source that page chose, at the price it was quoted. Minimum: 1."""
97
+ requireFields: NotRequired[list[Literal["verified"]]]
98
+ """Optional; omit it and routing is unchanged, with the cheapest source serving. Name the output fields this request must be able to return, for example `verified`, and it is served only by a source that returns every one of them. Fields you do not name are still returned whenever the serving source has them. This can raise your price: when the cheapest source cannot return a named field, a dearer source serves, and you are quoted and charged its price. A named field can still be absent on a profile that genuinely lacks it. Naming a combination that no single source returns together is refused as invalid input, with no charge."""
97
99
  source: NotRequired[list[str]]
98
100
  """Optional. Source ids to prefer, in order, taken from this endpoint's `lanes[].source.id` in /catalog or /apis. Omit it and the cheapest source serves, with automatic failover. Listed sources are tried first in the order given, then the others, unless `allowFallbacks` is false. A single source with `allowFallbacks` false is served only by that source at its price, quoted and charged exactly, with no failover. The price is that of the dearest source that may serve. An id that does not serve this endpoint is rejected as invalid input with no charge; a listed source that is not serving right now is refused with no charge, so omit `source` to be served by another. On a paginated walk, later pages must include the source that served page one, or omit `source`."""
99
101
  username: Required[str]
@@ -382,7 +384,7 @@ class RedditPostCommentsData(BaseModel):
382
384
  )
383
385
  media: list[RedditPostCommentsMedia] | None = Field(
384
386
  default=None,
385
- description="Photo, video, and GIF attachments on the post. Empty when the post has none.",
387
+ description="Photo, video, and GIF attachments on the post. Empty when the post has none; null when the serving source does not report attachments.",
386
388
  )
387
389
  next_cursor: str | None = Field(
388
390
  alias="nextCursor",
@@ -523,7 +525,8 @@ class RedditProfileData(BaseModel):
523
525
  description="Account username, without the u/ prefix. Populated whenever the provider has data for the entity."
524
526
  )
525
527
  verified: bool | None = Field(
526
- default=None, description="True when the account is verified by Reddit."
528
+ default=None,
529
+ description="True when the account is verified by Reddit. Null when the serving source does not report it.",
527
530
  )
528
531
 
529
532
 
@@ -122,7 +122,10 @@ class ThreadsPostData(BaseModel):
122
122
  alias="profilePicUrl",
123
123
  description="Profile picture URL of the author.",
124
124
  )
125
- quote_count: int = Field(alias="quoteCount", description="Number of quote posts.")
125
+ quote_count: int | None = Field(
126
+ alias="quoteCount",
127
+ description="Number of quote posts. Null when the source does not report it.",
128
+ )
126
129
  reply_count: int = Field(
127
130
  alias="replyCount", description="Number of replies to the post."
128
131
  )
@@ -442,7 +442,7 @@ class TiktokSearchTopInput(TypedDict, total=False):
442
442
  """Keyword to search for (e.g. "funny")."""
443
443
  region: NotRequired[str]
444
444
  """2-letter country code for the proxy location (e.g. US, GB, FR)."""
445
- requireFields: NotRequired[list[Literal["nextCursor"]]]
445
+ requireFields: NotRequired[list[Literal["contentType", "nextCursor"]]]
446
446
  """Optional; omit it and routing is unchanged, with the cheapest source serving. Name the output fields this request must be able to return, for example `nextCursor`, and it is served only by a source that returns every one of them. Fields you do not name are still returned whenever the serving source has them. This can raise your price: when the cheapest source cannot return a named field, a dearer source serves, and you are quoted and charged its price. A named field can still be absent on a record that genuinely lacks it. Naming a combination that no single source returns together is refused as invalid input, with no charge."""
447
447
  sortBy: NotRequired[Literal["relevance", "most-liked", "date-posted"]]
448
448
  """Sort order: relevance, most-liked, date-posted."""
@@ -1906,7 +1906,10 @@ class TiktokSearchTopItem(BaseModel):
1906
1906
  description="Populated whenever the provider has data for the entity."
1907
1907
  )
1908
1908
  comments: int
1909
- content_type: str = Field(alias="contentType")
1909
+ content_type: str | None = Field(
1910
+ alias="contentType",
1911
+ description="TikTok's own label for the post format, such as video, or null when the serving source does not report it.",
1912
+ )
1910
1913
  created_utc: float | None = Field(
1911
1914
  default=None,
1912
1915
  alias="createdUtc",
@@ -2465,7 +2468,10 @@ class TiktokVideoTranscriptData(BaseModel):
2465
2468
  id: str | None = Field(
2466
2469
  default=None, description="TikTok video id the transcript belongs to."
2467
2470
  )
2468
- language: str | None = None
2471
+ language: str | None = Field(
2472
+ default=None,
2473
+ description="Language of the caption track, or null when the serving source does not report it.",
2474
+ )
2469
2475
  transcript: str = Field(
2470
2476
  description="Populated whenever the provider has data for the entity."
2471
2477
  )
@@ -64,6 +64,8 @@ class TiktokShopProductInput(TypedDict, total=False):
64
64
  """Optional; omit it and routing is unchanged, with the cheapest source serving. Prefer sources whose typical response time (median over the trailing 30 days, as published on this endpoint's lane health) is under this many milliseconds; among those, the cheapest serves. This can raise your price: when the cheapest source misses the target, a faster and dearer one serves, and you are quoted and charged its price. If no source is that fast the request is still served, by whichever source offers the best speed for its price - it is never refused for being slow. Sources we have not timed are tried last. This is a preference, not a guarantee: the median describes past requests and is not a ceiling on this one, and it excludes any wait this request itself asks for. On a paginated walk it applies to the first page only: later pages stay with the source that page chose, at the price it was quoted. Minimum: 1."""
65
65
  region: NotRequired[str]
66
66
  """Two-letter country code for the proxy location used to access region-specific products (e.g. US, GB, FR). Defaults to US."""
67
+ requireFields: NotRequired[list[Literal["sellerLocation"]]]
68
+ """Optional; omit it and routing is unchanged, with the cheapest source serving. Name the output fields this request must be able to return, for example `sellerLocation`, and it is served only by a source that returns every one of them. Fields you do not name are still returned whenever the serving source has them. This can raise your price: when the cheapest source cannot return a named field, a dearer source serves, and you are quoted and charged its price. A named field can still be absent on a product that genuinely lacks it. Naming a combination that no single source returns together is refused as invalid input, with no charge."""
67
69
  source: NotRequired[list[str]]
68
70
  """Optional. Source ids to prefer, in order, taken from this endpoint's `lanes[].source.id` in /catalog or /apis. Omit it and the cheapest source serves, with automatic failover. Listed sources are tried first in the order given, then the others, unless `allowFallbacks` is false. A single source with `allowFallbacks` false is served only by that source at its price, quoted and charged exactly, with no failover. The price is that of the dearest source that may serve. An id that does not serve this endpoint is rejected as invalid input with no charge; a listed source that is not serving right now is refused with no charge, so omit `source` to be served by another. On a paginated walk, later pages must include the source that served page one, or omit `source`."""
69
71
  url: Required[str]
@@ -160,6 +162,8 @@ class TiktokShopShopProductsInput(TypedDict, total=False):
160
162
  """Optional; omit it and routing is unchanged, with the cheapest source serving. Prefer sources whose typical response time (median over the trailing 30 days, as published on this endpoint's lane health) is under this many milliseconds; among those, the cheapest serves. This can raise your price: when the cheapest source misses the target, a faster and dearer one serves, and you are quoted and charged its price. If no source is that fast the request is still served, by whichever source offers the best speed for its price - it is never refused for being slow. Sources we have not timed are tried last. This is a preference, not a guarantee: the median describes past requests and is not a ceiling on this one, and it excludes any wait this request itself asks for. On a paginated walk it applies to the first page only: later pages stay with the source that page chose, at the price it was quoted. Minimum: 1."""
161
163
  region: NotRequired[str]
162
164
  """Two-letter country code of the store's market (e.g. US)."""
165
+ requireFields: NotRequired[list[Literal["productCount", "shopRating"]]]
166
+ """Optional; omit it and routing is unchanged, with the cheapest source serving. Name the output fields this request must be able to return, for example `shopRating`, and it is served only by a source that returns every one of them. Fields you do not name are still returned whenever the serving source has them. This can raise your price: when the cheapest source cannot return a named field, a dearer source serves, and you are quoted and charged its price. A named field can still be absent on a store that genuinely lacks it. Naming a combination that no single source returns together is refused as invalid input, with no charge. On a paginated walk it applies to the first page only; later pages stay with the source that page chose, at the price it was quoted."""
163
167
  sortBy: NotRequired[Literal["top", "new_releases"]]
164
168
  """Product ordering within the store. Default: top."""
165
169
  source: NotRequired[list[str]]
@@ -284,7 +288,7 @@ class TiktokShopCreatorData(BaseModel):
284
288
  )
285
289
  gpm: float | None = Field(
286
290
  default=None,
287
- description="Gross merchandise value per thousand views. Zero when upstream does not publish it.",
291
+ description="Gross merchandise value per thousand views. Null when upstream does not publish it.",
288
292
  )
289
293
  handle: str = Field(
290
294
  description="TikTok handle of the creator, without the @. Populated whenever the provider has data for the entity."
@@ -316,7 +320,7 @@ class TiktokShopCreatorData(BaseModel):
316
320
  )
317
321
  rating: float | None = Field(
318
322
  default=None,
319
- description="Creator rating. Zero when upstream does not publish it.",
323
+ description="Creator rating. Null when upstream does not publish it.",
320
324
  )
321
325
  region: str | None = Field(
322
326
  default=None,
@@ -395,7 +399,10 @@ class TiktokShopProductData(BaseModel):
395
399
  )
396
400
  rating: float
397
401
  review_count: int = Field(alias="reviewCount")
398
- seller_location: str = Field(alias="sellerLocation")
402
+ seller_location: str | None = Field(
403
+ alias="sellerLocation",
404
+ description="Where the seller is based, or null when the serving source does not report it.",
405
+ )
399
406
  seller_name: str = Field(
400
407
  alias="sellerName",
401
408
  description="Populated whenever the provider has data for the entity.",
@@ -413,12 +420,15 @@ class TiktokShopProductReviewsData(BaseModel):
413
420
  alias="hasMore",
414
421
  description="True when more reviews are available beyond this page.",
415
422
  )
416
- rating: float = Field(description="Overall product score (1-5).")
423
+ rating: float | None = Field(
424
+ description="Overall product score (1-5), or null when the serving source does not report it."
425
+ )
417
426
  reviews: list[TiktokShopProductReviewsReview] = Field(
418
427
  description="Product reviews. Populated whenever the provider has data for the entity."
419
428
  )
420
- total_reviews: int = Field(
421
- alias="totalReviews", description="Total number of reviews for the product."
429
+ total_reviews: int | None = Field(
430
+ alias="totalReviews",
431
+ description="Total number of reviews for the product, or null when the serving source does not report it.",
422
432
  )
423
433
 
424
434
 
@@ -533,7 +543,10 @@ class TiktokShopShopProductsData(BaseModel):
533
543
  alias="nextCursor",
534
544
  description="Opaque cursor for the next page of products, or null when this lane has no more. Pass it back as cursor to continue.",
535
545
  )
536
- product_count: int = Field(alias="productCount")
546
+ product_count: int | None = Field(
547
+ alias="productCount",
548
+ description="Number of products the store has on sale, or null when the serving source does not report it.",
549
+ )
537
550
  products: list[TiktokShopShopProductsProduct] = Field(
538
551
  description="Populated whenever the provider has data for the entity."
539
552
  )
@@ -541,8 +554,14 @@ class TiktokShopShopProductsData(BaseModel):
541
554
  alias="shopName",
542
555
  description="Populated whenever the provider has data for the entity.",
543
556
  )
544
- shop_rating: float = Field(alias="shopRating")
545
- sold_count: int = Field(alias="soldCount")
557
+ shop_rating: float | None = Field(
558
+ alias="shopRating",
559
+ description="The store's rating out of 5, or null when the serving source does not report it.",
560
+ )
561
+ sold_count: int | None = Field(
562
+ alias="soldCount",
563
+ description="Units the store has sold across all its products, or null when the serving source does not report it.",
564
+ )
546
565
 
547
566
 
548
567
  class TiktokShopShopProductsProduct(BaseModel):
@@ -224,13 +224,13 @@ class TripadvisorSearchItem(BaseModel):
224
224
  default=None,
225
225
  description='Ranking string within its location (e.g. "#2 of 1,885 hotels in Paris").',
226
226
  )
227
- rating: float = Field(
228
- description="Average traveler rating out of 5. Populated whenever the provider has data for the entity."
227
+ rating: float | None = Field(
228
+ description="Average traveler rating out of 5; null for a place Tripadvisor has not rated (such as a city). Populated whenever the provider has data for the entity."
229
229
  )
230
230
  review_count: float | None = Field(
231
231
  default=None,
232
232
  alias="reviewCount",
233
- description="Total number of traveler reviews.",
233
+ description="Total number of traveler reviews; null when the source does not report it.",
234
234
  )
235
235
  title: str = Field(
236
236
  description="Place name. Populated whenever the provider has data for the entity."
@@ -743,7 +743,9 @@ class TwitterRepliesItem(BaseModel):
743
743
  description="Canonical x.com URL of the reply, with tracking query params stripped. Populated whenever the provider has data for the entity."
744
744
  )
745
745
  view_count: int | None = Field(
746
- default=None, alias="viewCount", description="Number of views of this reply."
746
+ default=None,
747
+ alias="viewCount",
748
+ description="Number of views of this reply. Null when the source does not report it, as for posts older than X view counts.",
747
749
  )
748
750
 
749
751
 
@@ -842,7 +844,11 @@ class TwitterSearchItem(BaseModel):
842
844
  url: str = Field(
843
845
  description="Populated whenever the provider has data for the entity."
844
846
  )
845
- view_count: int | None = Field(default=None, alias="viewCount")
847
+ view_count: int | None = Field(
848
+ default=None,
849
+ alias="viewCount",
850
+ description="Number of views. Null when the source does not report it, as for posts older than X view counts.",
851
+ )
846
852
 
847
853
 
848
854
  class TwitterSearchMedia(BaseModel):
@@ -34,6 +34,8 @@ class YoutubeChannelInput(TypedDict, total=False):
34
34
  """Optional. Source ids to skip for this request, taken from this endpoint's `lanes[].source.id`. The cheapest remaining source serves and the price is that of the dearest remaining source. An id that does not serve this endpoint, or that is also in `source`, is rejected as invalid input with no charge; skipping every source is rejected the same way."""
35
35
  preferLatencyUnderMs: NotRequired[int]
36
36
  """Optional; omit it and routing is unchanged, with the cheapest source serving. Prefer sources whose typical response time (median over the trailing 30 days, as published on this endpoint's lane health) is under this many milliseconds; among those, the cheapest serves. This can raise your price: when the cheapest source misses the target, a faster and dearer one serves, and you are quoted and charged its price. If no source is that fast the request is still served, by whichever source offers the best speed for its price - it is never refused for being slow. Sources we have not timed are tried last. This is a preference, not a guarantee: the median describes past requests and is not a ceiling on this one, and it excludes any wait this request itself asks for. On a paginated walk it applies to the first page only: later pages stay with the source that page chose, at the price it was quoted. Minimum: 1."""
37
+ requireFields: NotRequired[list[Literal["views"]]]
38
+ """Optional; omit it and routing is unchanged, with the cheapest source serving. Name the output fields this request must be able to return, for example `views`, and it is served only by a source that returns every one of them. Fields you do not name are still returned whenever the serving source has them. This can raise your price: when the cheapest source cannot return a named field, a dearer source serves, and you are quoted and charged its price. A named field can still be absent on a record that genuinely lacks it. Naming a combination that no single source returns together is refused as invalid input, with no charge."""
37
39
  source: NotRequired[list[str]]
38
40
  """Optional. Source ids to prefer, in order, taken from this endpoint's `lanes[].source.id` in /catalog or /apis. Omit it and the cheapest source serves, with automatic failover. Listed sources are tried first in the order given, then the others, unless `allowFallbacks` is false. A single source with `allowFallbacks` false is served only by that source at its price, quoted and charged exactly, with no failover. The price is that of the dearest source that may serve. An id that does not serve this endpoint is rejected as invalid input with no charge; a listed source that is not serving right now is refused with no charge, so omit `source` to be served by another. On a paginated walk, later pages must include the source that served page one, or omit `source`."""
39
41
 
@@ -89,6 +91,8 @@ class YoutubeChannelLivesInput(TypedDict, total=False):
89
91
  """Optional. Source ids to skip for this request, taken from this endpoint's `lanes[].source.id`. The cheapest remaining source serves and the price is that of the dearest remaining source. An id that does not serve this endpoint, or that is also in `source`, is rejected as invalid input with no charge; skipping every source is rejected the same way."""
90
92
  preferLatencyUnderMs: NotRequired[int]
91
93
  """Optional; omit it and routing is unchanged, with the cheapest source serving. Prefer sources whose typical response time (median over the trailing 30 days, as published on this endpoint's lane health) is under this many milliseconds; among those, the cheapest serves. This can raise your price: when the cheapest source misses the target, a faster and dearer one serves, and you are quoted and charged its price. If no source is that fast the request is still served, by whichever source offers the best speed for its price - it is never refused for being slow. Sources we have not timed are tried last. This is a preference, not a guarantee: the median describes past requests and is not a ceiling on this one, and it excludes any wait this request itself asks for. On a paginated walk it applies to the first page only: later pages stay with the source that page chose, at the price it was quoted. Minimum: 1."""
94
+ requireFields: NotRequired[list[Literal["lengthText"]]]
95
+ """Optional; omit it and routing is unchanged, with the cheapest source serving. Name the output fields this request must be able to return, for example `lengthText`, and it is served only by a source that returns every one of them. Fields you do not name are still returned whenever the serving source has them. This can raise your price: when the cheapest source cannot return a named field, a dearer source serves, and you are quoted and charged its price. A named field can still be absent on a live stream that genuinely lacks it. Naming a combination that no single source returns together is refused as invalid input, with no charge. On a paginated walk it applies to the first page only; later pages stay with the source that page chose, at the price it was quoted."""
92
96
  source: NotRequired[list[str]]
93
97
  """Optional. Source ids to prefer, in order, taken from this endpoint's `lanes[].source.id` in /catalog or /apis. Omit it and the cheapest source serves, with automatic failover. Listed sources are tried first in the order given, then the others, unless `allowFallbacks` is false. A single source with `allowFallbacks` false is served only by that source at its price, quoted and charged exactly, with no failover. The price is that of the dearest source that may serve. An id that does not serve this endpoint is rejected as invalid input with no charge; a listed source that is not serving right now is refused with no charge, so omit `source` to be served by another. On a paginated walk, later pages must include the source that served page one, or omit `source`."""
94
98
 
@@ -148,7 +152,7 @@ class YoutubeChannelVideosInput(TypedDict, total=False):
148
152
  """Optional. Source ids to skip for this request, taken from this endpoint's `lanes[].source.id`. The cheapest remaining source serves and the price is that of the dearest remaining source. An id that does not serve this endpoint, or that is also in `source`, is rejected as invalid input with no charge; skipping every source is rejected the same way."""
149
153
  preferLatencyUnderMs: NotRequired[int]
150
154
  """Optional; omit it and routing is unchanged, with the cheapest source serving. Prefer sources whose typical response time (median over the trailing 30 days, as published on this endpoint's lane health) is under this many milliseconds; among those, the cheapest serves. This can raise your price: when the cheapest source misses the target, a faster and dearer one serves, and you are quoted and charged its price. If no source is that fast the request is still served, by whichever source offers the best speed for its price - it is never refused for being slow. Sources we have not timed are tried last. This is a preference, not a guarantee: the median describes past requests and is not a ceiling on this one, and it excludes any wait this request itself asks for. On a paginated walk it applies to the first page only: later pages stay with the source that page chose, at the price it was quoted. Minimum: 1."""
151
- requireFields: NotRequired[list[Literal["views"]]]
155
+ requireFields: NotRequired[list[Literal["lengthText", "views"]]]
152
156
  """Optional; omit it and routing is unchanged, with the cheapest source serving. Name the output fields this request must be able to return, for example `views`, and it is served only by a source that returns every one of them. Fields you do not name are still returned whenever the serving source has them. This can raise your price: when the cheapest source cannot return a named field, a dearer source serves, and you are quoted and charged its price. A named field can still be absent on a video that genuinely lacks it. Naming a combination that no single source returns together is refused as invalid input, with no charge. On a paginated walk it applies to the first page only; later pages stay with the source that page chose, at the price it was quoted. A source that returns only a rounded or shortened value for a field does not count as returning it."""
153
157
  sort: NotRequired[Literal["latest", "popular"]]
154
158
  """Sort order."""
@@ -401,7 +405,9 @@ class YoutubeChannelData(BaseModel):
401
405
  description="Canonical URL of the channel page, tracking query parameters stripped.",
402
406
  )
403
407
  videos: int
404
- views: int
408
+ views: int | None = Field(
409
+ description="Lifetime view count across the channel's videos, or null when the serving source does not report it."
410
+ )
405
411
 
406
412
 
407
413
  class YoutubeChannelCommunityPostsData(BaseModel):
@@ -489,7 +495,10 @@ class YoutubeChannelLivesLive(BaseModel):
489
495
  default=None,
490
496
  description="URL of the live stream thumbnail image, tracking query parameters stripped.",
491
497
  )
492
- length_text: str = Field(alias="lengthText")
498
+ length_text: str | None = Field(
499
+ alias="lengthText",
500
+ description="Stream length as YouTube shows it, such as 3:29:31, or LIVE while it is streaming; null when the serving source does not report it.",
501
+ )
493
502
  published_time: str = Field(
494
503
  alias="publishedTime",
495
504
  description="Populated whenever the provider has data for the entity.",
@@ -500,7 +509,9 @@ class YoutubeChannelLivesLive(BaseModel):
500
509
  url: str = Field(
501
510
  description="Populated whenever the provider has data for the entity."
502
511
  )
503
- views: int
512
+ views: int = Field(
513
+ description='Views of a past stream, or people watching a stream that is live now. Every source reads it from YouTube\'s rounded label ("60K watching" is 60000), so it is approximate.'
514
+ )
504
515
 
505
516
 
506
517
  class YoutubeChannelPlaylistsData(BaseModel):
@@ -576,8 +587,8 @@ class YoutubeChannelShortsShort(BaseModel):
576
587
  default=None,
577
588
  description="URL of the short thumbnail image, tracking query parameters stripped.",
578
589
  )
579
- likes: int = Field(
580
- description="Public like count when supplied by the upstream response. Minimum: 0."
590
+ likes: int | None = Field(
591
+ description="Public like count, or null when the serving source does not report it. Minimum: 0."
581
592
  )
582
593
  title: str | None = Field(
583
594
  default=None,
@@ -622,7 +633,10 @@ class YoutubeChannelVideosVideo(BaseModel):
622
633
  default=None,
623
634
  description="URL of the video thumbnail image, tracking query parameters stripped.",
624
635
  )
625
- length_text: str = Field(alias="lengthText")
636
+ length_text: str | None = Field(
637
+ alias="lengthText",
638
+ description="Video length as YouTube shows it, such as 11:56, or null when the serving source does not report it.",
639
+ )
626
640
  published_time: str = Field(
627
641
  alias="publishedTime",
628
642
  description="Populated whenever the provider has data for the entity.",
File without changes
File without changes
File without changes
File without changes