@hunt-labs/bytekit-sdk 0.11.9 → 0.11.11

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.
@@ -153,7 +153,9 @@ export interface paths {
153
153
  put?: never;
154
154
  /**
155
155
  * Capture a screenshot
156
- * @description Sync by default (holds up to 28s). Pass `?async=true` to return 202 immediately.
156
+ * @description Sync by default (holds up to 28s). Pass `async: true` in the body or `?async=true` in the
157
+ * query string to return 202 immediately; either one is enough, and `false` in one never
158
+ * cancels `true` in the other.
157
159
  * Poll via GET /v1/screenshots/{id}.
158
160
  *
159
161
  * **Limits:** request bodies are capped at 512 KB. An oversized body
@@ -198,13 +200,15 @@ export interface paths {
198
200
  *
199
201
  * **The response shape is decided by your request, not by how we route it.** In precedence order:
200
202
  *
201
- * 1. `async: true` → **202** with a `ScrapeQueuedEnvelope` receipt, returned immediately. Poll `GET /v1/scrape/{id}` for the result.
203
+ * 1. `async: true` in the body, or `?async=true` in the query string (either one is enough; `false` in one never cancels `true` in the other) → **202** with a `ScrapeQueuedEnvelope` receipt, returned immediately. Poll `GET /v1/scrape/{id}` for the result.
202
204
  * 2. Otherwise, a request that needs a full page render — today that is `delay_ms > 0` — is **held open** until the render reaches a terminal state, then returns **200** with the content envelope (`success` or `failed`). If the render is still running when the hold window expires (28 seconds by default), the request returns the **202** receipt instead and the job continues in the background.
203
205
  * 3. Otherwise the request is served by the fast HTTP path and returns **200** with the content envelope, typically in under a second.
204
206
  *
205
207
  * **A failed fetch is a result, not a transport error.** An unreachable host, a refused connection, or a target whose bot protection defeats every proxy tier all come back on the same **200** as a `failed` envelope — never a 5xx. Narrow on the envelope's `status` before reading the body. A failure the fast path decides inline is recorded as a failed job, so its envelope normally carries that job's `id` and `GET /v1/scrape/{id}` returns the same envelope; if recording the failed job itself fails, the envelope still arrives on the same 200 with `id` set to `null` and there is nothing to poll. A failure a held render reaches carries that render's real `id`. Either way the request transfers no billable bytes and is charged nothing.
206
208
  *
207
- * So a 202 means one of exactly two things: you asked for one with `async: true`, or the hold window expired. `wait_for_selector` and `wait_until` are `ScreenshotRequest` options, not `ScrapeRequest` options — sending either to this endpoint returns `422 validation_error`, so neither can produce a 202 here.
209
+ * **A target that rate-limits us is not ByteKit rate-limiting you.** The `failed` envelope's `error.code` is `target_rate_limited` when the target rate-limits the request. On the fast path that means our proxy attempts end on an HTTP 429 and no bot protection is identified on any attempt, even if the browser fallback then fails or reaches only an unidentified block page; the inline failure carries `error.retry_after_seconds` when the target sent a usable `Retry-After`. On a held render the browser's own answer decides: it observes a 429 on the page itself, or it fails outright after the proxy attempts ended on an HTTP 429. A bot-protection verdict on an earlier fetch attempt does not keep a held render `blocked` when the browser then observes the 429. A held render never carries `error.retry_after_seconds`. Retrying a `target_rate_limited` failure later is likely to work. A held render whose browser reaches an unidentified 403 or 503 page after a proxy 429 is `blocked`. A 429 that bot protection sends as a block stays `blocked` when it is the answer that decides the code: the fast path's proxy attempts, or the browser render on a held render. Your own per-key limit is a separate case: it answers HTTP 429 `rate_limited` with a `Retry-After` header (see the `429` response).
210
+ *
211
+ * So a 202 means one of exactly two things: you asked for one with `async: true` or `?async=true`, or the hold window expired. `wait_for_selector` and `wait_until` are `ScreenshotRequest` options, not `ScrapeRequest` options — sending either to this endpoint returns `422 validation_error`, so neither can produce a 202 here.
208
212
  */
209
213
  post: operations["createScrape"];
210
214
  delete?: never;
@@ -249,6 +253,12 @@ export interface paths {
249
253
  * `BulkCompletedWebhook` contract: at most 500 complete items and 1 MiB,
250
254
  * followed by cursor recovery through `GET /v1/scrape/bulk/{id}` whenever
251
255
  * `recovery_required` is true.
256
+ *
257
+ * **Unknown keys.** An unknown key on an `items[]` entry, or at the top level of
258
+ * the body, is rejected with `422 validation_error`. An unknown key inside
259
+ * `defaults` is not: it is dropped without a warning and the request is accepted
260
+ * with `202`. The exception is `cookies` and `headers`, on an item or in `defaults`: they
261
+ * answer `400 validation_error`.
252
262
  */
253
263
  post: operations["createScrapeBulk"];
254
264
  delete?: never;
@@ -277,6 +287,17 @@ export interface paths {
277
287
  * stored, or whose object cannot be signed, is omitted from `formats` and
278
288
  * reported as `artifact_unavailable` in `warnings`. The private unsigned
279
289
  * storage URL is never returned.
290
+ *
291
+ * **Cancelled by the platform.** When the account can no longer spend (its bandwidth
292
+ * balance is exhausted, or the account is deleted) while items are still pending, ByteKit
293
+ * cancels the job itself. It then reads `status: cancelled` even though you never called
294
+ * `DELETE /v1/bulk/{id}`, and the cancellation sends no webhook.
295
+ *
296
+ * **Job ids from other create routes.** The job is looked up by account only, so the id
297
+ * of a job created by `POST /v1/fetch/bulk` or `POST /v1/bulk` is found here too, not a `404`.
298
+ * The items listed are the job's scrape rows: a fetch-bulk job's items appear, and a
299
+ * `POST /v1/bulk` job shows its scrape items but not its screenshots. An id from another
300
+ * account answers `404`.
280
301
  */
281
302
  get: operations["getScrapeBulk"];
282
303
  put?: never;
@@ -296,15 +317,20 @@ export interface paths {
296
317
  };
297
318
  /**
298
319
  * Fetch a URL (GET)
299
- * @description Direct HTTP fetch. Successful responses return the upstream response bytes verbatim;
300
- * metadata is returned in X-Fetch-* headers. Non-2xx upstream responses use the
301
- * `upstream_error` JSON envelope with the upstream HTTP status.
320
+ * @description Direct HTTP fetch. Metadata is returned in X-Fetch-* headers. What the body holds
321
+ * depends on `X-Fetch-Fast-Path`. When it is `true`, a successful response returns the
322
+ * upstream response bytes verbatim. When it is `false` the request fell back to a browser
323
+ * render, and the body is the rendered page rather than the bytes the target sent;
324
+ * `X-Fetch-Content-Length` is then the compressed size of that page. Non-2xx upstream
325
+ * responses use the `upstream_error` JSON envelope with the upstream HTTP status.
302
326
  */
303
327
  get: operations["getFetch"];
304
328
  put?: never;
305
329
  /**
306
330
  * Fetch a URL (POST)
307
- * @description Same as GET /v1/fetch but with a JSON request body.
331
+ * @description Same as GET /v1/fetch but with a JSON request body. The response is the same, including
332
+ * the `X-Fetch-Fast-Path` rule for what the body holds: the upstream bytes verbatim when
333
+ * it is `true`, the rendered page when it is `false`.
308
334
  *
309
335
  * **Limits:** request bodies are capped at 512 KB. An oversized body
310
336
  * returns a `400` with error code `request_too_large`.
@@ -373,6 +399,16 @@ export interface paths {
373
399
  * stored object, or completed items whose object cannot be signed, carry
374
400
  * `null`; the latter report `artifact_unavailable`. The private unsigned
375
401
  * storage URL is never returned.
402
+ *
403
+ * **Cancelled by the platform.** When the account can no longer spend (its bandwidth
404
+ * balance is exhausted, or the account is deleted) while items are still pending, ByteKit
405
+ * cancels the job itself. It then reads `status: cancelled` even though you never called
406
+ * `DELETE /v1/bulk/{id}`, and the cancellation sends no webhook.
407
+ *
408
+ * **Job ids from other create routes.** The job is looked up by account only, so the id
409
+ * of a job created by `POST /v1/scrape/bulk` or `POST /v1/bulk` is found here too, not a
410
+ * `404`, with the job envelope and `items: []`: only items fetched through
411
+ * `POST /v1/fetch/bulk` are listed. An id from another account answers `404`.
376
412
  */
377
413
  get: operations["getFetchBulk"];
378
414
  put?: never;
@@ -436,7 +472,19 @@ export interface paths {
436
472
  path?: never;
437
473
  cookie?: never;
438
474
  };
439
- /** Get bulk job status */
475
+ /**
476
+ * Get bulk job status
477
+ * @description Returns the job envelope. Items are listed by `GET /v1/bulk/{id}/screenshots`.
478
+ *
479
+ * **Cancelled by the platform.** When the account can no longer spend (its bandwidth
480
+ * balance is exhausted, or the account is deleted) while items are still pending, ByteKit
481
+ * cancels the job itself. It then reads `status: cancelled` even though you never called
482
+ * `DELETE /v1/bulk/{id}`, and the cancellation sends no webhook.
483
+ *
484
+ * **Job ids from other create routes.** The job is looked up by account only, so the id
485
+ * of a job created by `POST /v1/scrape/bulk` or `POST /v1/fetch/bulk` is found here too, not
486
+ * a `404`, with that job's envelope. An id from another account answers `404`.
487
+ */
440
488
  get: operations["getBulk"];
441
489
  put?: never;
442
490
  post?: never;
@@ -567,6 +615,20 @@ export interface paths {
567
615
  * `X-ByteKit-Event: sitemap.failed` so receivers can dispatch on the
568
616
  * header without parsing the body shape.
569
617
  *
618
+ * The webhook body is `{ event, data }`. For a job the worker ran, `data` is not a
619
+ * `SitemapResponse`:
620
+ *
621
+ * - `sitemap.completed` `data` carries `id`, `url`, `strategy`, `status`,
622
+ * `total_urls`, `sources`, `total_bytes`, `results_url`, `warnings`,
623
+ * `metadata`, `compact` and `billing`.
624
+ * - `sitemap.failed` `data` carries `id`, `url`, `strategy`, `status`,
625
+ * `error_code`, `error_message`, `warnings` and `metadata`.
626
+ *
627
+ * In both, `url` is the host as `scheme://host`, and `warnings` is the
628
+ * worker's own warnings or `null`. When the request is answered from a cached job
629
+ * (`cache: hit`), the `sitemap.completed` `data` is instead the full job object, the
630
+ * same fields as a `SitemapResponse`.
631
+ *
570
632
  * **Limits:** request bodies are capped at 512 KB. An oversized body
571
633
  * returns a `400` with error code `request_too_large`.
572
634
  */
@@ -740,7 +802,11 @@ export interface paths {
740
802
  put?: never;
741
803
  /**
742
804
  * Create Stripe checkout session
743
- * @description Creates a Stripe Checkout Session for subscription sign-up.
805
+ * @description Creates an Elements-mode Stripe Checkout session for subscription sign-up
806
+ * and returns its client secret. The dashboard mounts Stripe's Payment
807
+ * Element on `client_secret` and the user pays in-page; the plan activates
808
+ * asynchronously once Stripe's subscription webhook settles. The card paid
809
+ * with becomes the customer's default when none is set.
744
810
  */
745
811
  post: operations["createCheckout"];
746
812
  delete?: never;
@@ -758,7 +824,11 @@ export interface paths {
758
824
  };
759
825
  get?: never;
760
826
  put?: never;
761
- /** Create Stripe billing portal session */
827
+ /**
828
+ * Retired billing-portal compatibility terminal
829
+ * @description Returns 410 for every request and reads no body. Card update, cancellation and
830
+ * invoice history all stay in the dashboard at `/settings/billing`.
831
+ */
762
832
  post: operations["createPortal"];
763
833
  delete?: never;
764
834
  options?: never;
@@ -776,9 +846,8 @@ export interface paths {
776
846
  get?: never;
777
847
  put?: never;
778
848
  /**
779
- * PAYG onboarding
780
- * @description Creates a Stripe customer and setup-mode Checkout Session to collect
781
- * a payment method without charging. For pay-as-you-go accounts.
849
+ * Legacy card-setup compatibility terminal
850
+ * @description Returns 410. Card setup moved to `POST /v1/billing/payment-methods/setup`.
782
851
  */
783
852
  post: operations["registerPayg"];
784
853
  delete?: never;
@@ -798,10 +867,11 @@ export interface paths {
798
867
  put?: never;
799
868
  /**
800
869
  * One-time dollar deposit
801
- * @description Creates a hosted Stripe Checkout session for a deposit into the account's
802
- * USD balance and returns its URL. The caller redirects the user to
803
- * `checkout_url`; the balance is credited asynchronously by the
804
- * `payment_intent.succeeded` webhook once payment completes. The balance
870
+ * @description Creates an Elements-mode Stripe Checkout session for a deposit into the
871
+ * account's USD balance and returns its client secret. The dashboard mounts
872
+ * Stripe's Payment Element on `client_secret` and the user pays in-page; the
873
+ * balance is credited asynchronously once Stripe's payment webhook settles.
874
+ * The card paid with becomes the customer's default when none is set. The balance
805
875
  * never expires and pays for usage beyond the included allowance, for
806
876
  * bandwidth and search credits alike, at the plan's rate when it is used.
807
877
  */
@@ -819,15 +889,22 @@ export interface paths {
819
889
  path?: never;
820
890
  cookie?: never;
821
891
  };
822
- get?: never;
892
+ /**
893
+ * Read whether the plan is cancelling
894
+ * @description Whether the subscription is set to end at the end of the current period, read from Stripe on each call.
895
+ */
896
+ get: operations["getCancellation"];
823
897
  put?: never;
824
898
  /**
825
- * Legacy cancellation compatibility terminal
826
- * @description Returns 410. Customer cancellation is initiated through the hosted
827
- * Billing Portal and projected through Stripe webhooks.
899
+ * Cancel the plan at the period end
900
+ * @description Sets the subscription to end at the end of the current period instead of renewing; the plan stays active until then and the account then moves to Pay As You Go. A plan change booked for the period end is released first. Send the current cancellation disclosure revision in the `Billing-Disclosure-Revision` header: without it, or with a stale one, the call answers `409 billing_disclosure_stale` with the current terms.
828
901
  */
829
902
  post: operations["cancelSubscription"];
830
- delete?: never;
903
+ /**
904
+ * Keep a cancelling plan
905
+ * @description Undoes a pending cancellation, so the subscription renews at the end of the current period as before.
906
+ */
907
+ delete: operations["keepSubscription"];
831
908
  options?: never;
832
909
  head?: never;
833
910
  patch?: never;
@@ -846,7 +923,10 @@ export interface paths {
846
923
  */
847
924
  get: operations["getPlanChange"];
848
925
  put?: never;
849
- /** Change subscription plan */
926
+ /**
927
+ * Change subscription plan
928
+ * @description A plan change made while the plan is cancelling clears the pending cancellation, so the subscription keeps renewing.
929
+ */
850
930
  post: operations["changePlan"];
851
931
  /**
852
932
  * Revoke a scheduled plan change
@@ -865,7 +945,10 @@ export interface paths {
865
945
  path?: never;
866
946
  cookie?: never;
867
947
  };
868
- /** List Stripe invoices */
948
+ /**
949
+ * List Stripe invoices
950
+ * @description Invoices are ordered newest first. Page older with `starting_after` set to the last `id` of the previous page.
951
+ */
869
952
  get: operations["listInvoices"];
870
953
  put?: never;
871
954
  post?: never;
@@ -991,6 +1074,7 @@ export interface paths {
991
1074
  /**
992
1075
  * Detach a payment method
993
1076
  * @description Detaches the specified payment method from the Stripe customer.
1077
+ * Removing the last card also turns auto-topup off.
994
1078
  */
995
1079
  delete: operations["deletePaymentMethod"];
996
1080
  options?: never;
@@ -1123,8 +1207,11 @@ export interface paths {
1123
1207
  put?: never;
1124
1208
  /**
1125
1209
  * Bootstrap account
1126
- * @description First-time account creation for a Clerk-authenticated user.
1127
- * Idempotent — returns 200 if the account already exists, 201 on first creation.
1210
+ * @description First-time bootstrap for a Clerk-authenticated user: the caller joins the
1211
+ * account of the newest pending invite for the session email (on a live
1212
+ * account), or, with no such invite, a new account is created.
1213
+ * Idempotent — returns 200 if the account already exists, 201 on the first
1214
+ * successful bootstrap (either outcome).
1128
1215
  * Does not require an existing membership (allowNoMembership=true).
1129
1216
  */
1130
1217
  post: operations["bootstrapAccount"];
@@ -1145,8 +1232,9 @@ export interface paths {
1145
1232
  put?: never;
1146
1233
  /**
1147
1234
  * Accept current Terms of Service
1148
- * @description Records the authenticated account's acceptance of the current Terms of
1149
- * Service version (clickwrap re-acceptance). The server always records the
1235
+ * @description Records the signed-in person's own acceptance of the current Terms of
1236
+ * Service version (clickwrap). The record is per person, so each member of
1237
+ * an account accepts for themselves. The server always records the
1150
1238
  * current version — the client cannot accept an arbitrary version. The
1151
1239
  * client IP and User-Agent are captured as legal evidence. Requires an
1152
1240
  * active membership.
@@ -1169,9 +1257,10 @@ export interface paths {
1169
1257
  put?: never;
1170
1258
  /**
1171
1259
  * Mark onboarding as finished
1172
- * @description Records that the account left the dashboard's onboarding flow through one
1173
- * of its exits, so `onboarding_completed` on GET /v1/account reads true from
1174
- * then on. Idempotent: a repeat call keeps the first timestamp and still
1260
+ * @description Records that the signed-in person left the dashboard's onboarding flow
1261
+ * through one of its exits, so both `onboarding_completed` (the account) and
1262
+ * `user_onboarding_completed` (this person) on GET /v1/account read true
1263
+ * from then on. Idempotent: a repeat call keeps the first timestamps and still
1175
1264
  * answers 200. Requires an active membership (admin or member).
1176
1265
  */
1177
1266
  post: operations["completeOnboarding"];
@@ -1461,6 +1550,14 @@ export interface components {
1461
1550
  details?: unknown;
1462
1551
  };
1463
1552
  };
1553
+ /** @description The vendor-masked `503` body of `POST /v1/search`. */
1554
+ CreateSearchResponse503: {
1555
+ /**
1556
+ * @description Fixed vendor-masked error code. Always `search_provider_error`; the upstream provider's identity and failure detail are withheld by design.
1557
+ * @enum {string}
1558
+ */
1559
+ error: "search_provider_error";
1560
+ };
1464
1561
  /**
1465
1562
  * @description Item-local terminal artifact failure. The item's stable id remains usable for paginated recovery, but the requested stored content or signed reference could not be produced. Wherever this code is raised the URL field it describes is `null`; a private object-storage URL is never returned as a substitute for it. Endpoints that do not raise this code document their own fallback — see `image_url` on `GET /v1/bulk/{id}/screenshots`.
1466
1563
  *
@@ -1484,6 +1581,10 @@ export interface components {
1484
1581
  formats?: {
1485
1582
  raw?: string | null;
1486
1583
  markdown?: string | null;
1584
+ /** @description The item's `formats.json` result (`data`, `validated`, `model`), present only when the job requested a `json` format and the serialized result fits the 8,192-character bound; `null` when the item has no result. */
1585
+ json?: {
1586
+ [key: string]: unknown;
1587
+ } | null;
1487
1588
  links?: null | (string | components["schemas"]["ScrapeScoredLink"])[];
1488
1589
  images?: null | (string | components["schemas"]["ScrapeScoredImage"])[];
1489
1590
  };
@@ -1645,10 +1746,11 @@ export interface components {
1645
1746
  BillingNode: {
1646
1747
  /**
1647
1748
  * @description The unmultiplied basis of the charge. For byte-billed endpoints this is
1648
- * the upstream wire bytes actually transferred. For screenshots and
1649
- * recordings it is the Phase 1 HTML fetch's wire bytes — the only proxied
1650
- * traffic in the happy path — never the size of the returned PNG/JPEG/MP4
1651
- * artifact.
1749
+ * the upstream wire bytes actually transferred. For a page served by the
1750
+ * hosted-browser tier it is the browser's full measured transfer. For
1751
+ * screenshots and recordings it is the Phase 1 HTML fetch's wire bytes — the
1752
+ * only proxied traffic in the happy path — never the size of the returned
1753
+ * PNG/JPEG/MP4 artifact.
1652
1754
  * @example 1024
1653
1755
  */
1654
1756
  raw_bytes: number;
@@ -1671,11 +1773,19 @@ export interface components {
1671
1773
  /** Format: uri */
1672
1774
  url: string;
1673
1775
  /**
1776
+ * @description What to return. Each entry is either a string format (`raw`, `markdown`, `links`
1777
+ * or `images`) or a `json` object entry that extracts structured data from the page.
1778
+ * The string `"json"` is not a format value; the `json` entry is an object, described
1779
+ * by `ScrapeRequestJsonFormat`. A list may hold at most one `json` entry, and a list
1780
+ * holding only the `json` entry still captures `raw`. The `json` entry is accepted on
1781
+ * `POST /v1/scrape`, `POST /v1/scrape/bulk` and `POST /v1/bulk` (scrape entries);
1782
+ * monitor `formats` accept the string formats alone. Its result is `formats.json` on the
1783
+ * response, and its charge is described on `ScrapeRequestJsonFormat`.
1674
1784
  * @default [
1675
1785
  * "raw"
1676
1786
  * ]
1677
1787
  */
1678
- formats: ("raw" | "markdown" | "links" | "images")[];
1788
+ formats: (components["schemas"]["ScrapeRequestFormatsItem"] | components["schemas"]["ScrapeRequestJsonFormat"])[];
1679
1789
  /** @default US */
1680
1790
  country: string;
1681
1791
  /**
@@ -1683,10 +1793,10 @@ export interface components {
1683
1793
  * @default 0
1684
1794
  */
1685
1795
  delay_ms: number;
1686
- /** @default 30000 */
1796
+ /** @default 60000 */
1687
1797
  timeout_ms: number;
1688
1798
  /**
1689
- * @description When true, the request returns 202 with a `ScrapeQueuedEnvelope` receipt immediately and the scrape runs in the background; poll `GET /v1/scrape/{id}` for the result. This is the only way to ASK for a receipt, and it outranks every routing consequence: with `async: false` (the default) a browser-path request is held to completion instead of being receipted. A 202 can still arrive with `async: false`, but only when the hold window expires.
1799
+ * @description When true, the request returns 202 with a `ScrapeQueuedEnvelope` receipt immediately and the scrape runs in the background; poll `GET /v1/scrape/{id}` for the result. The `?async=true` query parameter is a second spelling of this field: the request is async when either one says true, and `false` in one never cancels `true` in the other. Asking for a receipt this way outranks every routing consequence: when neither is set (the default) a browser-path request is held to completion instead of being receipted. A 202 can still arrive without either, but only when the hold window expires.
1690
1800
  * @default false
1691
1801
  */
1692
1802
  async: boolean;
@@ -1791,6 +1901,54 @@ export interface components {
1791
1901
  */
1792
1902
  x_internal_scrape_path?: "lean-forced";
1793
1903
  };
1904
+ /**
1905
+ * @description A string entry of `ScrapeRequest.formats`.
1906
+ * @enum {string}
1907
+ */
1908
+ ScrapeRequestFormatsItem: "raw" | "markdown" | "links" | "images";
1909
+ /**
1910
+ * @description The `json` entry of `ScrapeRequest.formats`: structured extraction over the scraped
1911
+ * page, using the same extractor as `POST /v1/schema`.
1912
+ *
1913
+ * **Charge.** Each `json` entry carries a flat per-extraction credit charge, on top of the
1914
+ * scrape's own bandwidth charge and never scaled by the scrape's factors. It is charged
1915
+ * only when the extraction validates (`formats.json.validated` is `true`). The credits are
1916
+ * reserved at admission in every billing mode and released again when the extraction does
1917
+ * not validate.
1918
+ *
1919
+ * **Where it applies.** The entry is accepted in `formats` on `POST /v1/scrape`, in
1920
+ * `defaults.formats` and each `items[].formats` of `POST /v1/scrape/bulk`, and in the same
1921
+ * fields of scrape entries on `POST /v1/bulk`. A list holds at most one `json` entry. On
1922
+ * the bulk endpoints each scrape item carries its own `formats.json` result; an item's own
1923
+ * `json` entry replaces the one in `defaults`.
1924
+ *
1925
+ * **Errors.** A `schema` the extractor cannot take is refused with
1926
+ * `422 schema_incompatible`, and a deployment with no extraction provider refuses the
1927
+ * request with `503 provider_unavailable`. Both are refused before anything is drawn. Once
1928
+ * the page is scraped, an extraction that does not validate never fails the scrape: the
1929
+ * result carries `validated: false` and `data: null`, with an extraction warning in
1930
+ * `warnings`.
1931
+ */
1932
+ ScrapeRequestJsonFormat: {
1933
+ /** @enum {string} */
1934
+ type: "json";
1935
+ /**
1936
+ * @description JSON Schema describing the desired output. It is held to the same guards as the
1937
+ * `schema` field of `POST /v1/schema`: serialized size at most 50 KB, nesting depth at
1938
+ * most 8, it must compile under Ajv, and it must be normalizable into the extractor's
1939
+ * strict subset (root `type: object`, and only the keyword allowlist given there).
1940
+ */
1941
+ schema: {
1942
+ [key: string]: unknown;
1943
+ };
1944
+ /**
1945
+ * @description Extraction model. Defaults to `openai/gpt-oss-20b` when omitted.
1946
+ * @enum {string}
1947
+ */
1948
+ model?: "openai/gpt-oss-20b" | "openai/gpt-oss-120b";
1949
+ /** @description Optional natural-language extraction hint. */
1950
+ prompt?: string;
1951
+ };
1794
1952
  ScrapeScoredLink: {
1795
1953
  /** Format: uri */
1796
1954
  url: string;
@@ -1815,8 +1973,11 @@ export interface components {
1815
1973
  cols: number;
1816
1974
  };
1817
1975
  ScrapeWarning: {
1818
- /** @enum {string} */
1819
- code: "lossy_table" | "complex_math" | "unsupported_element" | "extraction_fallback" | "truncated" | "query_no_match" | "mode_disabled_fallback" | "artifact_unavailable" | "llm_clean_unavailable" | "llm_clean_failed" | "low_quality_extraction" | "fragment_menu_stripped";
1976
+ /**
1977
+ * @description Machine-readable warning code. `truncated` means the markdown was cut to fit the requested `tokenBudget`. `short_content` means a successful browser capture of an HTML page produced very little readable text (under 100 characters), which usually means the page needed an interaction such as scrolling or clicking that the capture did not perform; a genuinely short page can raise it too. `frames_skipped` means a browser capture left out one or more iframes (cross-origin ones, which the capture cannot read, or same-origin ones that failed or were still loading), so content inside them may be missing from the returned HTML. `short_content` and `frames_skipped` are advisory: they never change the response status, error code or billed bytes.
1978
+ * @enum {string}
1979
+ */
1980
+ code: "lossy_table" | "complex_math" | "unsupported_element" | "extraction_fallback" | "truncated" | "query_no_match" | "mode_disabled_fallback" | "artifact_unavailable" | "llm_clean_unavailable" | "llm_clean_failed" | "low_quality_extraction" | "fragment_menu_stripped" | "extract_validation_failed" | "exhausted_retries" | "content_truncated" | "model_refusal" | "empty_extraction" | "short_content" | "frames_skipped";
1820
1981
  message: string;
1821
1982
  element: string | null;
1822
1983
  };
@@ -1841,6 +2002,21 @@ export interface components {
1841
2002
  links?: string[] | components["schemas"]["ScrapeScoredLink"][];
1842
2003
  /** @description Plain URL strings by default. When markdownIncludeMedia=true, an array of ScrapeScoredImage objects. */
1843
2004
  images?: string[] | components["schemas"]["ScrapeScoredImage"][];
2005
+ /**
2006
+ * @description The result of the request's `json` format entry. Present on every outcome of a
2007
+ * request that carried one. A failed extraction never fails the scrape: it sets
2008
+ * `validated` to `false` and adds an extraction warning code to `warnings`.
2009
+ */
2010
+ json?: {
2011
+ /** @description The extracted object, or `null` whenever `validated` is `false`. */
2012
+ data: {
2013
+ [key: string]: unknown;
2014
+ } | null;
2015
+ /** @description Whether the extraction produced output matching the schema. The `json` credits are charged only when `true`. */
2016
+ validated: boolean;
2017
+ /** @description The extraction model that ran. */
2018
+ model: string;
2019
+ };
1844
2020
  };
1845
2021
  ScrapeMetadata: {
1846
2022
  title: string | null;
@@ -1952,6 +2128,8 @@ export interface components {
1952
2128
  * @description Compressed wire bytes transferred for this request — the basis for
1953
2129
  * bandwidth-billed plans. Reflects what crossed the network on your behalf
1954
2130
  * (e.g. gzip/brotli-compressed size), not the decompressed content length.
2131
+ * A page served by the hosted-browser tier reports the browser's full
2132
+ * measured transfer instead: every response it loaded plus the requests it sent.
1955
2133
  */
1956
2134
  content_length: number;
1957
2135
  status_code: number | null;
@@ -2023,9 +2201,11 @@ export interface components {
2023
2201
  id: string | null;
2024
2202
  error: {
2025
2203
  /** @enum {string} */
2026
- code: "validation_error" | "invalid_url" | "request_too_large" | "payload_too_large" | "unsupported_content_type" | "rate_limited" | "upstream_error" | "blocked" | "timeout" | "internal_error";
2204
+ code: "validation_error" | "invalid_url" | "request_too_large" | "payload_too_large" | "unsupported_content_type" | "rate_limited" | "upstream_error" | "blocked" | "target_rate_limited" | "timeout" | "internal_error";
2027
2205
  message: string;
2028
2206
  http_status?: number;
2207
+ /** @description Whole seconds the target site asked us to wait before the next request. Present only with `code: target_rate_limited`, only on the inline `POST /v1/scrape` failure the fast path decides, and only when the target sent a usable `Retry-After` (delta-seconds, or an HTTP-date still in the future, converted to seconds; values above 2147483647 are reported as 2147483647). Informational: ByteKit never enforces it on your next request. A held render (`delay_ms > 0`), `GET /v1/scrape/{id}` and webhooks omit it, because the value is relative to the moment the target answered. */
2208
+ retry_after_seconds?: number;
2029
2209
  /** Format: date-time */
2030
2210
  failed_at: string;
2031
2211
  };
@@ -2066,7 +2246,10 @@ export interface components {
2066
2246
  FetchRequest: {
2067
2247
  /** Format: uri */
2068
2248
  url: string;
2069
- /** @default US */
2249
+ /**
2250
+ * @description Two-letter country code. Either case is accepted; the value is upper-cased.
2251
+ * @default US
2252
+ */
2070
2253
  country: string;
2071
2254
  /** @default 60000 */
2072
2255
  timeout_ms: number;
@@ -2093,6 +2276,11 @@ export interface components {
2093
2276
  device: "desktop" | "mobile";
2094
2277
  /** @default null */
2095
2278
  viewport: components["schemas"]["Viewport"] | null;
2279
+ /**
2280
+ * @description When true, the request returns 202 immediately and the screenshot is captured in the background; poll `GET /v1/screenshots/{id}`. The `?async=true` query parameter is a second spelling of this field: the request is async when either one says true, and `false` in one never cancels `true` in the other.
2281
+ * @default false
2282
+ */
2283
+ async: boolean;
2096
2284
  /** @default false */
2097
2285
  full_page: boolean;
2098
2286
  /**
@@ -2429,9 +2617,26 @@ export interface components {
2429
2617
  captured_at: string;
2430
2618
  };
2431
2619
  SitemapRequest: {
2432
- /** Format: uri */
2620
+ /**
2621
+ * Format: uri
2622
+ * @description The site to discover. Sitemap discovery is host-scoped (`robots.txt`
2623
+ * and `/sitemap.xml` live at the host root), so only the scheme and host
2624
+ * are used: a path, query string or fragment is accepted but ignored,
2625
+ * and the `202` response carries a `warnings` entry saying so. A bare
2626
+ * host, or a host with just a trailing `/`, produces no warning.
2627
+ */
2433
2628
  url: string;
2434
2629
  /**
2630
+ * @description How much discovery work the job does.
2631
+ *
2632
+ * - `quick` — reads `robots.txt` and the XML sitemaps only. Every
2633
+ * result has `source: sitemap`.
2634
+ * - `standard` — the `quick` sources, then fills any remaining
2635
+ * `max_urls` budget with URLs from your account's completed scrapes of
2636
+ * the host in the last 90 days (`source: known`).
2637
+ * - `deep` — the `standard` sources, then crawls page links outward from
2638
+ * the URLs found so far, up to `max_depth` levels, until `max_urls` is
2639
+ * reached (`source: links`).
2435
2640
  * @default standard
2436
2641
  * @enum {string}
2437
2642
  */
@@ -2440,7 +2645,11 @@ export interface components {
2440
2645
  max_depth: number;
2441
2646
  /** @default 5000 */
2442
2647
  max_urls: number;
2443
- /** @default null */
2648
+ /**
2649
+ * @description Accepted, stored and echoed back on the job, but it has no effect: the
2650
+ * worker logs that the trigger is not implemented and ignores it.
2651
+ * @default null
2652
+ */
2444
2653
  process: {
2445
2654
  action?: string;
2446
2655
  options?: {
@@ -2469,6 +2678,17 @@ export interface components {
2469
2678
  SitemapResponse: {
2470
2679
  /** @example sm_01j9abc123 */
2471
2680
  id: string;
2681
+ /**
2682
+ * @description On the `202` creation response, the submitted URL after ByteKit has
2683
+ * normalised it, when that URL carried a path, query string or fragment
2684
+ * (discovery still ran on the host only; see `warnings`). Normalisation
2685
+ * lowercases the scheme and host, puts an international host in
2686
+ * punycode, percent-encodes non-ASCII characters and trims surrounding
2687
+ * spaces, so the value can differ from the string you sent. In every
2688
+ * other case (a bare-host request, `GET /v1/sitemap/{id}` and the
2689
+ * webhook `data` object) it is the host the job is scoped to, as
2690
+ * `scheme://host`.
2691
+ */
2472
2692
  url: string;
2473
2693
  strategy: string;
2474
2694
  max_depth: number;
@@ -2507,17 +2727,42 @@ export interface components {
2507
2727
  * for jobs that completed before the billing node was persisted.
2508
2728
  */
2509
2729
  billing?: components["schemas"]["BillingNode"];
2730
+ /**
2731
+ * @description On the `202` creation response, a single entry naming the path, query
2732
+ * string or fragment of the submitted `url` that host-scoped discovery
2733
+ * ignored. It never fails the request. It is not stored with the job:
2734
+ * `GET /v1/sitemap/{id}` and the webhook `data` object report the
2735
+ * worker's own warnings, or `null`.
2736
+ */
2510
2737
  warnings: string[] | null;
2738
+ /**
2739
+ * @description Why a `failed` job failed; `null` otherwise. One of the values below. It is typed as
2740
+ * a free string so that a code added later does not break a client.
2741
+ *
2742
+ * - `job_timeout` — the job ran past its time limit.
2743
+ * - `blocked` — the host sits behind a WAF that blocks every discovery
2744
+ * phase, so the job did not run.
2745
+ * - `no_urls_found` — discovery finished with no URLs for the host.
2746
+ * - `internal_error` — an unexpected error while discovering.
2747
+ * - `worker_crash` — the job sat in `processing` far past the recovery
2748
+ * threshold, so it was failed as a worker crash.
2749
+ */
2511
2750
  error_code: string | null;
2512
2751
  error_message: string | null;
2513
2752
  compact: boolean;
2753
+ /** @description The `process` value from the request, echoed back. It has no effect. */
2514
2754
  process: Record<string, never> | null;
2515
2755
  metadata: Record<string, never> | null;
2516
2756
  /** Format: date-time */
2517
2757
  created_at: string;
2518
2758
  /** Format: date-time */
2519
2759
  completed_at: string | null;
2520
- /** Format: date-time */
2760
+ /**
2761
+ * Format: date-time
2762
+ * @description When the job and its results expire: 90 days after the job completes. `null` until the
2763
+ * job completes, and on a failed job. A `cache: hit` response keeps the expiry of the job
2764
+ * that answered it.
2765
+ */
2521
2766
  expires_at: string | null;
2522
2767
  };
2523
2768
  WebhookDeliveryResponse: {
@@ -2528,7 +2773,7 @@ export interface components {
2528
2773
  * @example bulk.completed
2529
2774
  * @enum {string}
2530
2775
  */
2531
- event_type: "bulk.completed" | "scrape.completed" | "scrape.failed" | "monitor.change_detected" | "monitor.captured" | "sitemap.completed" | "sitemap.failed";
2776
+ event_type: "bulk.completed" | "scrape.completed" | "scrape.failed" | "monitor.change_detected" | "monitor.captured" | "monitor.suspended" | "sitemap.completed" | "sitemap.failed";
2532
2777
  target_url: string;
2533
2778
  /** @enum {string} */
2534
2779
  status: "pending" | "delivered" | "failed" | "exhausted";
@@ -2727,7 +2972,7 @@ export interface components {
2727
2972
  /** @description Whether the account admin wants an email when bandwidth reaches 100 % of the plan limit. */
2728
2973
  bandwidth_100_enabled: boolean;
2729
2974
  };
2730
- /** @description The Terms of Service version this account has accepted. An empty string means the account has not accepted the Terms yet; acceptance is recorded only by `POST /v1/account/accept-terms`, never by bootstrap (issue #5055). The dashboard diffs this against the published current version to decide whether to show the re-acceptance prompt. */
2975
+ /** @description The Terms of Service version the calling person has accepted. The record is per person, not per account: each member of an account accepts for themselves. An empty string means this person has never accepted the Terms; acceptance is recorded only by `POST /v1/account/accept-terms`, never by bootstrap (issues #5055, #5057). The dashboard diffs this against the published current version to decide whether to show the re-acceptance prompt. */
2731
2976
  terms_version: string;
2732
2977
  /** Format: date-time */
2733
2978
  created_at: string;
@@ -2735,6 +2980,8 @@ export interface components {
2735
2980
  has_activity: boolean;
2736
2981
  /** @description True once a member of the account left onboarding through one of its exits (POST /v1/account/complete-onboarding). Never reset. With `has_activity` it gates the dashboard: the app shows the guided onboarding flow until either one is true, so a user whose first request failed can still reach the dashboard. */
2737
2982
  onboarding_completed: boolean;
2983
+ /** @description True once the calling person left onboarding through one of its exits (POST /v1/account/complete-onboarding). Never reset. False sends this person through the guided onboarding flow even when the account itself is active or finished onboarding, so a teammate invited into an existing account still accepts the Terms and sees the API key once. */
2984
+ user_onboarding_completed: boolean;
2738
2985
  /** @description True when the account has a Stripe subscription, keyed on the same `stripe_subscription_id` column that GET /v1/billing/change-plan's `no_subscription` guard tests — so a client can use it to decide whether that endpoint will answer at all. Stays TRUE while a subscription is mid-cancellation (cancelled but running to the period end): the subscription still exists and a booked plan change is still revocable. It is a boolean, not the bearer path's `subscription` object: this response has no role-dependent fields, so a non-admin member receives it too, and plan pricing does not belong there. */
2739
2986
  has_subscription: boolean;
2740
2987
  };
@@ -2765,7 +3012,7 @@ export interface components {
2765
3012
  /** @description Whether the account admin wants an email when bandwidth reaches 100 % of the plan limit. */
2766
3013
  bandwidth_100_enabled: boolean;
2767
3014
  };
2768
- /** @description The Terms of Service version this account has accepted. An empty string means the account has not accepted the Terms yet; acceptance is recorded only by `POST /v1/account/accept-terms`, never by bootstrap (issue #5055). The dashboard diffs this against the published current version to decide whether to show the re-acceptance prompt. */
3015
+ /** @description The Terms of Service version the calling person has accepted. The record is per person, not per account: each member of an account accepts for themselves. An empty string means this person has never accepted the Terms; acceptance is recorded only by `POST /v1/account/accept-terms`, never by bootstrap (issues #5055, #5057). The dashboard diffs this against the published current version to decide whether to show the re-acceptance prompt. */
2769
3016
  terms_version: string;
2770
3017
  /** @description True when the account has a Stripe subscription, keyed on the same `stripe_subscription_id` column that GET /v1/billing/change-plan's `no_subscription` guard tests. */
2771
3018
  has_subscription: boolean;
@@ -2883,6 +3130,45 @@ export interface components {
2883
3130
  "application/json": components["schemas"]["Error"];
2884
3131
  };
2885
3132
  };
3133
+ /**
3134
+ * @description Unauthorized. The request carried no valid credential, and no work was
3135
+ * performed. The unified `Error` envelope carries one of the codes below
3136
+ * in `error.code`; match on the code, never on the prose.
3137
+ *
3138
+ * - `invalid_api_key` — a bearer API key was presented and rejected:
3139
+ * unknown, revoked, expired or malformed. The bearer-only operations
3140
+ * (`/v1/webhook-deliveries*` among them) also return it when no
3141
+ * `Authorization` header is sent. `GET /v1/account` is the exception
3142
+ * to "malformed": it returns `invalid_api_key` only for a key that
3143
+ * starts `sk_test_` or `sk_live_` and is unknown, revoked or expired.
3144
+ * - `unauthorized` — the `Authorization` header is absent or malformed on
3145
+ * an operation that also accepts a dashboard session (the dual-auth and
3146
+ * billing operations). `GET /v1/account` also returns it, for no
3147
+ * `Authorization` header and for any bearer value that does not start
3148
+ * `sk_test_` or `sk_live_` (that value is checked as a dashboard
3149
+ * session token).
3150
+ *
3151
+ * Not retryable as-is: supply a valid API key first.
3152
+ */
3153
+ Unauthorized: {
3154
+ headers: {
3155
+ [name: string]: unknown;
3156
+ };
3157
+ content: {
3158
+ /**
3159
+ * @example {
3160
+ * "status": "failed",
3161
+ * "error": {
3162
+ * "code": "invalid_api_key",
3163
+ * "message": "Missing or invalid API key.",
3164
+ * "http_status": 401,
3165
+ * "failed_at": "2026-01-15T12:00:00Z"
3166
+ * }
3167
+ * }
3168
+ */
3169
+ "application/json": components["schemas"]["Error"];
3170
+ };
3171
+ };
2886
3172
  };
2887
3173
  parameters: {
2888
3174
  /**
@@ -2902,7 +3188,16 @@ export interface components {
2902
3188
  */
2903
3189
  ClientSurfaceMarker: string;
2904
3190
  FetchUrl: string;
3191
+ /** @description Two-letter country code. Either case is accepted; the value is upper-cased. */
2905
3192
  FetchCountry: string;
3193
+ /**
3194
+ * @description A JSON-encoded object, URL-encoded in the query string. It is echoed back base64-encoded in
3195
+ * the `X-Fetch-Custom` response header so callers can correlate the response to caller-side
3196
+ * state. Capped at 4096 UTF-8 bytes after JSON serialization, and not part of the cache key.
3197
+ * A value that is not valid JSON answers `422 validation_error` ("custom must be a
3198
+ * JSON-encoded object"); valid JSON that is not an object is also rejected with `422`.
3199
+ */
3200
+ FetchCustom: string;
2906
3201
  FetchTimeoutMs: number;
2907
3202
  /** @description How long a freshly fetched URL may be served from cache. `0` skips the cache read; cache-eligible fresh results are still written with the default 7-day TTL so later non-zero-TTL callers can HIT. Safety-classified WAF husks remain live-only and are not written. Accepts `Nh` (hours, up to 168h), `Nd` (days, up to 7d), or the integer `0`. Examples: `0`, `48h`, `2d`. Invalid values receive a 422 validation_error with an actionable message. */
2908
3203
  FetchCacheTtl: string | 0;
@@ -2941,9 +3236,10 @@ export interface components {
2941
3236
  XFetchURL: string;
2942
3237
  /**
2943
3238
  * @description Byte length of the response body served on this request (integer as string) — NOT the
2944
- * billing basis. The body is always the upstream response bytes, so this equals the upstream wire byte
2945
- * count. Billing always reads the upstream compressed wire bytes from `X-Raw-Bytes` /
2946
- * `X-Billable-Bytes`, on every path.
3239
+ * billing basis. When `X-Fetch-Fast-Path` is `true` the body is the upstream response
3240
+ * bytes, so this equals the upstream wire byte count. When it is `false` the body is the
3241
+ * rendered page, and this is that page's compressed size. Billing always reads the
3242
+ * compressed wire bytes from `X-Raw-Bytes` / `X-Billable-Bytes`, on every path.
2947
3243
  */
2948
3244
  XFetchContentLength: string;
2949
3245
  XFetchCreditsCharged: string;
@@ -3034,6 +3330,7 @@ export interface operations {
3034
3330
  "application/json": components["schemas"]["AccountBearerResponse"] | components["schemas"]["AccountSessionResponse"];
3035
3331
  };
3036
3332
  };
3333
+ 401: components["responses"]["Unauthorized"];
3037
3334
  /** @description Rate limit exceeded (`rate_limited`). Only reachable when authenticated via Clerk session (the 60-request/60-second per-user window) — the bearer and in-process auth branches are not rate-limited at this endpoint. Carries a `Retry-After` header derived from the same clock as the window reset. */
3038
3335
  429: {
3039
3336
  headers: {
@@ -3386,6 +3683,7 @@ export interface operations {
3386
3683
  createScreenshot: {
3387
3684
  parameters: {
3388
3685
  query?: {
3686
+ /** @description Query-string spelling of the body `async` field. `true` returns the 202 immediately; any other value is ignored. */
3389
3687
  async?: boolean;
3390
3688
  };
3391
3689
  header?: never;
@@ -3491,7 +3789,25 @@ export interface operations {
3491
3789
  "application/json": components["schemas"]["Error"];
3492
3790
  };
3493
3791
  };
3792
+ 401: components["responses"]["Unauthorized"];
3494
3793
  402: components["responses"]["PaymentRequired"];
3794
+ /**
3795
+ * @description The target is on ByteKit's blocklist. Nothing is captured and nothing is billed.
3796
+ * The unified `Error` envelope carries one of two codes:
3797
+ *
3798
+ * - `host_forbidden` — a blocked domain, any `.gov` host, or a blocked port.
3799
+ * `details` is `{ host }`.
3800
+ * - `path_forbidden` — an authentication-style path such as a login page.
3801
+ * `details` is `{ path }`.
3802
+ */
3803
+ 403: {
3804
+ headers: {
3805
+ [name: string]: unknown;
3806
+ };
3807
+ content: {
3808
+ "application/json": components["schemas"]["Error"];
3809
+ };
3810
+ };
3495
3811
  /**
3496
3812
  * @description Validation error, or a screenshot that failed inside the sync hold.
3497
3813
  * The two carry DIFFERENT bodies (issue #2679):
@@ -3580,6 +3896,7 @@ export interface operations {
3580
3896
  "application/json": components["schemas"]["ScreenshotResponse"];
3581
3897
  };
3582
3898
  };
3899
+ 401: components["responses"]["Unauthorized"];
3583
3900
  /** @description Resource not found. */
3584
3901
  404: {
3585
3902
  headers: {
@@ -3593,7 +3910,10 @@ export interface operations {
3593
3910
  };
3594
3911
  createScrape: {
3595
3912
  parameters: {
3596
- query?: never;
3913
+ query?: {
3914
+ /** @description Query-string spelling of the body `async` field. `true` returns the 202 receipt immediately; any other value is ignored. Either spelling turns async on, and `false` in one never cancels `true` in the other. */
3915
+ async?: boolean;
3916
+ };
3597
3917
  header?: never;
3598
3918
  path?: never;
3599
3919
  cookie?: never;
@@ -3624,7 +3944,7 @@ export interface operations {
3624
3944
  };
3625
3945
  };
3626
3946
  responses: {
3627
- /** @description Scrape reached a terminal state and the body is that terminal envelope: `success` carrying content, or `failed` carrying the error envelope. Returned by the fast HTTP path in one round trip, and by a browser-path request without `async: true` once its render reaches a terminal state inside the hold window. A held render that ends in failure answers 200 with the same `failed` envelope `GET /v1/scrape/{id}` returns — narrow on `status` before reading the body. A definitive upstream outcome is a result, not a transport error: an unreachable host, a refused connection, or a target whose bot protection defeats every proxy tier all answer 200 with the `failed` envelope, never a 5xx. An inline failure is recorded as a failed job, so its envelope normally carries that job's `id` and polling it returns the same envelope; `id` is `null` only when recording the failed job itself failed. `error.http_status` is present only when a real upstream HTTP status is known. */
3947
+ /** @description Scrape reached a terminal state and the body is that terminal envelope: `success` carrying content, or `failed` carrying the error envelope. Returned by the fast HTTP path in one round trip, and by a browser-path request without `async: true` or `?async=true` once its render reaches a terminal state inside the hold window. A held render that ends in failure answers 200 with the same `failed` envelope `GET /v1/scrape/{id}` returns — narrow on `status` before reading the body. A definitive upstream outcome is a result, not a transport error: an unreachable host, a refused connection, or a target whose bot protection defeats every proxy tier all answer 200 with the `failed` envelope, never a 5xx. An inline failure is recorded as a failed job, so its envelope normally carries that job's `id` and polling it returns the same envelope; `id` is `null` only when recording the failed job itself failed. `error.http_status` is present only when a real upstream HTTP status is known. */
3628
3948
  200: {
3629
3949
  headers: {
3630
3950
  /** @description Stable scrape identifier (also present on the envelope as `id`). */
@@ -3647,7 +3967,7 @@ export interface operations {
3647
3967
  "X-Scrape-Status-Code"?: number;
3648
3968
  /** @description Compressed wire bytes — the basis for bandwidth billing. */
3649
3969
  "X-Scrape-Content-Length"?: number;
3650
- /** @description Uncompressed body byte count measured before any billing multiplication. */
3970
+ /** @description Compressed wire byte count of the body, measured before any billing multiplication. It is not the decompressed size. */
3651
3971
  "X-Raw-Bytes"?: number;
3652
3972
  /** @description Chargeable bytes after applying the billing multiplier. Equals round(X-Raw-Bytes × X-Billing-Multiplier). */
3653
3973
  "X-Billable-Bytes"?: number;
@@ -3675,9 +3995,9 @@ export interface operations {
3675
3995
  "X-Scrape-Markdown-URL"?: string;
3676
3996
  /** @description Byte length of the markdown artifact. Present only on fast-path responses when formats includes markdown. */
3677
3997
  "X-Scrape-Markdown-Length"?: number;
3678
- /** @description Legacy numeric form of the tier that served: 1 datacenter, 2 residential, 3 mobile. Omitted for the lean-browser tier, which has no numeric form. Deprecated — use X-Scrape-Proxy-Tier-Label. */
3998
+ /** @description Legacy numeric form of the tier that served: 1 datacenter, 2 residential, 3 mobile. Omitted for the lean-browser and hosted-browser tiers, which have no numeric form. Deprecated — use X-Scrape-Proxy-Tier-Label. */
3679
3999
  "X-Scrape-Proxy-Tier"?: number;
3680
- /** @description The proxy tier that actually served this request's fetch, after any escalation — never the tier first attempted. One of datacenter, residential, mobile, lean. Diagnostic only: it is never an input to routing, billing, caching or escalation. Present on sync fast-path responses. Omitted on a cache hit, which replayed stored bytes and ran no tier; and on responses the fast path did not serve. A third omission — a response replayed from stored bytes after this request's own cache lookup missed, which reports X-Scrape-Cache: miss and likewise ran no tier — exists only as an internal deploy-skew safeguard and is not reachable through this API. */
4000
+ /** @description The proxy tier that actually served this request's fetch, after any escalation — never the tier first attempted. One of datacenter, residential, mobile, lean, hosted_browser. Diagnostic only: it is never an input to routing, billing, caching or escalation. Present on sync fast-path responses. Omitted on a cache hit, which replayed stored bytes and ran no tier; and on responses the fast path did not serve. A third omission — a response replayed from stored bytes after this request's own cache lookup missed, which reports X-Scrape-Cache: miss and likewise ran no tier — exists only as an internal deploy-skew safeguard and is not reachable through this API. */
3681
4001
  "X-Scrape-Proxy-Tier-Label"?: string;
3682
4002
  /** @description WAF vendor detected on the target, if any (diagnostic). May be "suspected" when a low-confidence fail-open block marker was served. Omitted when no WAF is detected. */
3683
4003
  "X-Scrape-Waf"?: string;
@@ -3691,7 +4011,7 @@ export interface operations {
3691
4011
  "application/json": components["schemas"]["ScrapeSuccessEnvelope"] | components["schemas"]["ScrapeErrorEnvelope"];
3692
4012
  };
3693
4013
  };
3694
- /** @description Scrape accepted for background processing; the body is a receipt, not content. Returned when `async: true` was requested, or when a browser-path request's hold window expired before the render finished. Poll `GET /v1/scrape/{id}` for the result. */
4014
+ /** @description Scrape accepted for background processing; the body is a receipt, not content. Returned when `async: true` or `?async=true` was requested, or when a browser-path request's hold window expired before the render finished. Poll `GET /v1/scrape/{id}` for the result. */
3695
4015
  202: {
3696
4016
  headers: {
3697
4017
  /** @description Stable scrape identifier for the queued job. */
@@ -3727,8 +4047,12 @@ export interface operations {
3727
4047
  "application/json": components["schemas"]["Error"];
3728
4048
  };
3729
4049
  };
4050
+ 401: components["responses"]["Unauthorized"];
3730
4051
  402: components["responses"]["PaymentRequired"];
3731
- /** @description Validation error. */
4052
+ /**
4053
+ * @description Validation error. A `json` format entry whose `schema` the extractor cannot take is
4054
+ * refused with `schema_incompatible`, before anything is drawn.
4055
+ */
3732
4056
  422: {
3733
4057
  headers: {
3734
4058
  [name: string]: unknown;
@@ -3755,6 +4079,19 @@ export interface operations {
3755
4079
  "application/json": components["schemas"]["Error"];
3756
4080
  };
3757
4081
  };
4082
+ /**
4083
+ * @description The request carried a `json` format entry and JSON extraction is unavailable on this
4084
+ * deployment (`provider_unavailable`). It is refused before anything is drawn. A
4085
+ * terminal upstream failure is never a `503`: it is a `200` result, described above.
4086
+ */
4087
+ 503: {
4088
+ headers: {
4089
+ [name: string]: unknown;
4090
+ };
4091
+ content: {
4092
+ "application/json": components["schemas"]["Error"];
4093
+ };
4094
+ };
3758
4095
  };
3759
4096
  };
3760
4097
  getScrape: {
@@ -3771,12 +4108,47 @@ export interface operations {
3771
4108
  /** @description Scrape state (queued, success, or failed). */
3772
4109
  200: {
3773
4110
  headers: {
4111
+ /** @description Stable scrape identifier (also present on the envelope as `id`). Present on a completed or failed scrape; absent while it is still queued or processing. */
4112
+ "X-Scrape-ID"?: string;
4113
+ /** @description Envelope status discriminator, mirrored as a header for streaming consumers. Present on a completed or failed scrape; absent while it is still queued or processing. */
4114
+ "X-Scrape-Status"?: "success" | "failed" | "queued";
4115
+ /** @description The originally requested URL, before any redirects. Present on a completed or failed scrape; absent while it is still queued or processing. */
4116
+ "X-Scrape-URL"?: string;
4117
+ /** @description Content-Type of the scraped response body. Present on a completed or failed scrape; absent while it is still queued or processing. */
4118
+ "X-Scrape-Content-Type"?: string;
4119
+ /** @description Compressed wire bytes — the basis for bandwidth billing. Present on a completed or failed scrape; absent while it is still queued or processing. */
4120
+ "X-Scrape-Content-Length"?: number;
4121
+ /** @description Credits charged for this scrape (multiplier applied to base 1.0 per format). Present on a completed or failed scrape; absent while it is still queued or processing. */
4122
+ "X-Scrape-Credits-Charged"?: number;
4123
+ /** @description Handler elapsed time in milliseconds. X-Scrape-Elapsed-Ms emits the same value on gateway slow-path responses. Present on a completed or failed scrape; absent while it is still queued or processing. */
4124
+ "X-Scrape-Duration-Ms"?: number;
4125
+ /** @description End-to-end elapsed time in milliseconds. Alias for X-Scrape-Duration-Ms; both are emitted on gateway slow-path responses. Present on a completed or failed scrape; absent while it is still queued or processing. */
4126
+ "X-Scrape-Elapsed-Ms"?: number;
4127
+ /** @description Timestamp when the scrape row was created. Present on a completed or failed scrape; absent while it is still queued or processing. */
4128
+ "X-Scrape-Created-At"?: string;
4129
+ /** @description Timestamp when the scrape completed. Omitted if not yet completed. Present on a completed or failed scrape whose row records a completion time; absent while it is still queued or processing. */
4130
+ "X-Scrape-Completed-At"?: string;
4131
+ /** @description Expiry timestamp for the scrape artifact. Omitted if no retention applies. Present on a completed or failed scrape whose row records an expiry; absent while it is still queued or processing. */
4132
+ "X-Scrape-Expires-At"?: string;
4133
+ /** @description The URL after following redirects. Present on a completed or failed scrape whose row records a final URL; absent while it is still queued or processing. */
4134
+ "X-Scrape-Final-URL"?: string;
4135
+ /** @description HTTP status code returned by the target site. Present on a completed or failed scrape whose row records a target status code; absent while it is still queued or processing. */
4136
+ "X-Scrape-Status-Code"?: number;
4137
+ /** @description Cache outcome — `hit` = served from cache, `miss` = freshly fetched, `bypass` = `cache_ttl=0` requested. On GET present only on a failed scrape whose stored cache disposition is hit, miss or bypass; a completed scrape does not carry it, nor does a queued or processing one. */
4138
+ "X-Scrape-Cache"?: "hit" | "miss" | "bypass";
4139
+ /** @description Compressed wire byte count of the body, measured before any billing multiplication. It is not the decompressed size. Present on a completed or failed scrape; absent while it is still queued or processing. */
4140
+ "X-Raw-Bytes"?: number;
4141
+ /** @description Chargeable bytes after applying the billing multiplier. Equals round(X-Raw-Bytes × X-Billing-Multiplier). Present on a completed or failed scrape; absent while it is still queued or processing. */
4142
+ "X-Billable-Bytes"?: number;
4143
+ /** @description Bandwidth cost multiplier (e.g. 1.0 for a `raw`-only scrape, 1.5 when `markdown` is also requested). Cache hits compose the endpoint format factor, which is a separate number from this one: 0.5 for an unprocessed-source scrape, 0.75 with markdown. Excludes the `clean_markdown` surcharge: when `clean_markdown: true` and the clean succeeded, the settled usage is 3× this header's value, so this header does not predict the amount you are billed. The response body's `billing` node is the authoritative surface — it DOES carry the `clean_markdown` factor, so its `multiplier` and `billed_bytes` are what you are charged. Where the two disagree, the node is correct. Present on a completed or failed scrape; absent while it is still queued or processing. */
4144
+ "X-Billing-Multiplier"?: number;
3774
4145
  [name: string]: unknown;
3775
4146
  };
3776
4147
  content: {
3777
4148
  "application/json": components["schemas"]["ScrapeEnvelope"];
3778
4149
  };
3779
4150
  };
4151
+ 401: components["responses"]["Unauthorized"];
3780
4152
  /** @description Resource not found. */
3781
4153
  404: {
3782
4154
  headers: {
@@ -3836,7 +4208,7 @@ export interface operations {
3836
4208
  items?: {
3837
4209
  /** Format: uri */
3838
4210
  url: string;
3839
- formats?: ("raw" | "markdown" | "links" | "images")[];
4211
+ formats?: (("raw" | "markdown" | "links" | "images") | components["schemas"]["ScrapeRequestJsonFormat"])[];
3840
4212
  country?: string;
3841
4213
  delay_ms?: number;
3842
4214
  timeout_ms?: number;
@@ -3869,7 +4241,7 @@ export interface operations {
3869
4241
  * "raw"
3870
4242
  * ]
3871
4243
  */
3872
- formats?: ("raw" | "markdown" | "links" | "images")[];
4244
+ formats?: (("raw" | "markdown" | "links" | "images") | components["schemas"]["ScrapeRequestJsonFormat"])[];
3873
4245
  /** @default US */
3874
4246
  country?: string;
3875
4247
  /** @default 0 */
@@ -3967,7 +4339,38 @@ export interface operations {
3967
4339
  "application/json": components["schemas"]["Error"];
3968
4340
  };
3969
4341
  };
4342
+ 401: components["responses"]["Unauthorized"];
3970
4343
  402: components["responses"]["PaymentRequired"];
4344
+ /**
4345
+ * @description One or more URLs in the request are on ByteKit's blocklist. The whole request is
4346
+ * rejected before anything is queued or billed. This body is NOT the unified `Error`
4347
+ * envelope: it carries no `status`, `http_status` or `failed_at`. `blocked` lists every
4348
+ * offending URL with the rule that matched (`domain`, `tld`, `port` or `path`) and the
4349
+ * code that rule maps to (`host_forbidden` for the first three, `path_forbidden` for
4350
+ * `path`).
4351
+ */
4352
+ 403: {
4353
+ headers: {
4354
+ [name: string]: unknown;
4355
+ };
4356
+ content: {
4357
+ "application/json": {
4358
+ error: {
4359
+ /** @enum {string} */
4360
+ code: "url_forbidden";
4361
+ /** @example One or more URLs in this bulk request are blocked. */
4362
+ message: string;
4363
+ };
4364
+ blocked: {
4365
+ url: string;
4366
+ /** @enum {string} */
4367
+ rule_type: "domain" | "tld" | "port" | "path";
4368
+ /** @enum {string} */
4369
+ error_code: "host_forbidden" | "path_forbidden";
4370
+ }[];
4371
+ };
4372
+ };
4373
+ };
3971
4374
  /**
3972
4375
  * @description Validation error. `bulk_too_large` is returned when the item count
3973
4376
  * exceeds the account plan's `max_bulk_size` cap (also surfaced as
@@ -4089,6 +4492,7 @@ export interface operations {
4089
4492
  };
4090
4493
  };
4091
4494
  };
4495
+ 401: components["responses"]["Unauthorized"];
4092
4496
  /** @description Resource not found. */
4093
4497
  404: {
4094
4498
  headers: {
@@ -4104,10 +4508,19 @@ export interface operations {
4104
4508
  parameters: {
4105
4509
  query: {
4106
4510
  url: components["parameters"]["FetchUrl"];
4511
+ /** @description Two-letter country code. Either case is accepted; the value is upper-cased. */
4107
4512
  country?: components["parameters"]["FetchCountry"];
4108
4513
  timeout_ms?: components["parameters"]["FetchTimeoutMs"];
4109
4514
  /** @description How long a freshly fetched URL may be served from cache. `0` skips the cache read; cache-eligible fresh results are still written with the default 7-day TTL so later non-zero-TTL callers can HIT. Safety-classified WAF husks remain live-only and are not written. Accepts `Nh` (hours, up to 168h), `Nd` (days, up to 7d), or the integer `0`. Examples: `0`, `48h`, `2d`. Invalid values receive a 422 validation_error with an actionable message. */
4110
4515
  cache_ttl?: components["parameters"]["FetchCacheTtl"];
4516
+ /**
4517
+ * @description A JSON-encoded object, URL-encoded in the query string. It is echoed back base64-encoded in
4518
+ * the `X-Fetch-Custom` response header so callers can correlate the response to caller-side
4519
+ * state. Capped at 4096 UTF-8 bytes after JSON serialization, and not part of the cache key.
4520
+ * A value that is not valid JSON answers `422 validation_error` ("custom must be a
4521
+ * JSON-encoded object"); valid JSON that is not an object is also rejected with `422`.
4522
+ */
4523
+ custom?: components["parameters"]["FetchCustom"];
4111
4524
  };
4112
4525
  header?: never;
4113
4526
  path?: never;
@@ -4133,7 +4546,7 @@ export interface operations {
4133
4546
  "X-Fetch-Waf-Vendor": components["headers"]["XFetchWafVendor"];
4134
4547
  "X-Fetch-Content-Type": components["headers"]["XFetchContentType"];
4135
4548
  "X-Fetch-Custom": components["headers"]["XFetchCustom"];
4136
- /** @description Uncompressed body byte count measured before any billing multiplication. */
4549
+ /** @description Compressed wire byte count of the body, measured before any billing multiplication. It is not the decompressed size. */
4137
4550
  "X-Raw-Bytes"?: number;
4138
4551
  /** @description Chargeable bytes after applying the billing multiplier. Equals round(X-Raw-Bytes × X-Billing-Multiplier). */
4139
4552
  "X-Billable-Bytes"?: number;
@@ -4160,6 +4573,7 @@ export interface operations {
4160
4573
  "application/json": components["schemas"]["Error"];
4161
4574
  };
4162
4575
  };
4576
+ 401: components["responses"]["Unauthorized"];
4163
4577
  402: components["responses"]["PaymentRequired"];
4164
4578
  /**
4165
4579
  * @description Validation error (e.g. slow-path-only field), or a fetch that failed for a
@@ -4174,9 +4588,10 @@ export interface operations {
4174
4588
  * failure, such as a host that does not resolve. This is a result about the URL,
4175
4589
  * not an outage of this API, so it is a `4xx` rather than `502` or `503`. No
4176
4590
  * upstream HTTP status was received, so `error.http_status` reports `422`,
4177
- * mirroring what was served — unlike the relayed `upstream_error` under `502`
4178
- * below, whose status is the target's own. The request transfers no billable
4179
- * bytes and is charged nothing (#4669).
4591
+ * mirroring what was served — unlike the relayed `upstream_error` under `503`
4592
+ * below, whose `error.http_status` is the target's own. A target `502` or `504`
4593
+ * ends here too whenever it does not meet the condition for `503` below. The
4594
+ * request transfers no billable bytes and is charged nothing (#4669).
4180
4595
  */
4181
4596
  422: {
4182
4597
  headers: {
@@ -4206,7 +4621,12 @@ export interface operations {
4206
4621
  * `error.http_status` reports. Read `error.code` to tell them apart.
4207
4622
  *
4208
4623
  * - **`upstream_error`** — the target returned HTTP `502` or `504`, relayed here as
4209
- * `503`. Cloudflare fronts this API and replaces a clean origin 502 or 504 with its
4624
+ * `503`. This happens only when the escalation ladder ended on that answer, or when a
4625
+ * cached copy of it is served. A `502` or `504` is not terminal, so ByteKit first
4626
+ * retries it through its proxy tiers and the browser fallback; if the ladder ends any
4627
+ * other way, or a bot-protection vendor was seen on the way, the request answers
4628
+ * `422` (`upstream_error` or `blocked`) instead.
4629
+ * Cloudflare fronts this API and replaces a clean origin 502 or 504 with its
4210
4630
  * own generic `text/plain` error page, discarding the envelope before it reaches
4211
4631
  * you, while a 503 is passed through unchanged. The body's `error.http_status`
4212
4632
  * still reports the **true upstream status**, `502` or `504` — not `503` — and is
@@ -4268,7 +4688,7 @@ export interface operations {
4268
4688
  "X-Fetch-Waf-Vendor": components["headers"]["XFetchWafVendor"];
4269
4689
  "X-Fetch-Content-Type": components["headers"]["XFetchContentType"];
4270
4690
  "X-Fetch-Custom": components["headers"]["XFetchCustom"];
4271
- /** @description Uncompressed body byte count measured before any billing multiplication. */
4691
+ /** @description Compressed wire byte count of the body, measured before any billing multiplication. It is not the decompressed size. */
4272
4692
  "X-Raw-Bytes"?: number;
4273
4693
  /** @description Chargeable bytes after applying the billing multiplier. Equals round(X-Raw-Bytes × X-Billing-Multiplier). */
4274
4694
  "X-Billable-Bytes"?: number;
@@ -4295,6 +4715,7 @@ export interface operations {
4295
4715
  "application/json": components["schemas"]["Error"];
4296
4716
  };
4297
4717
  };
4718
+ 401: components["responses"]["Unauthorized"];
4298
4719
  402: components["responses"]["PaymentRequired"];
4299
4720
  /**
4300
4721
  * @description Validation error (e.g. malformed JSON, unsupported fetch format, or slow-path-only
@@ -4309,9 +4730,10 @@ export interface operations {
4309
4730
  * failure, such as a host that does not resolve. This is a result about the URL,
4310
4731
  * not an outage of this API, so it is a `4xx` rather than `502` or `503`. No
4311
4732
  * upstream HTTP status was received, so `error.http_status` reports `422`,
4312
- * mirroring what was served — unlike the relayed `upstream_error` under `502`
4313
- * below, whose status is the target's own. The request transfers no billable
4314
- * bytes and is charged nothing (#4669).
4733
+ * mirroring what was served — unlike the relayed `upstream_error` under `503`
4734
+ * below, whose `error.http_status` is the target's own. A target `502` or `504`
4735
+ * ends here too whenever it does not meet the condition for `503` below. The
4736
+ * request transfers no billable bytes and is charged nothing (#4669).
4315
4737
  */
4316
4738
  422: {
4317
4739
  headers: {
@@ -4341,7 +4763,12 @@ export interface operations {
4341
4763
  * `error.http_status` reports. Read `error.code` to tell them apart.
4342
4764
  *
4343
4765
  * - **`upstream_error`** — the target returned HTTP `502` or `504`, relayed here as
4344
- * `503`. Cloudflare fronts this API and replaces a clean origin 502 or 504 with its
4766
+ * `503`. This happens only when the escalation ladder ended on that answer, or when a
4767
+ * cached copy of it is served. A `502` or `504` is not terminal, so ByteKit first
4768
+ * retries it through its proxy tiers and the browser fallback; if the ladder ends any
4769
+ * other way, or a bot-protection vendor was seen on the way, the request answers
4770
+ * `422` (`upstream_error` or `blocked`) instead.
4771
+ * Cloudflare fronts this API and replaces a clean origin 502 or 504 with its
4345
4772
  * own generic `text/plain` error page, discarding the envelope before it reaches
4346
4773
  * you, while a 503 is passed through unchanged. The body's `error.http_status`
4347
4774
  * still reports the **true upstream status**, `502` or `504` — not `503` — and is
@@ -4456,7 +4883,38 @@ export interface operations {
4456
4883
  "application/json": components["schemas"]["Error"];
4457
4884
  };
4458
4885
  };
4886
+ 401: components["responses"]["Unauthorized"];
4459
4887
  402: components["responses"]["PaymentRequired"];
4888
+ /**
4889
+ * @description One or more URLs in the request are on ByteKit's blocklist. The whole request is
4890
+ * rejected before anything is queued or billed. This body is NOT the unified `Error`
4891
+ * envelope: it carries no `status`, `http_status` or `failed_at`. `blocked` lists every
4892
+ * offending URL with the rule that matched (`domain`, `tld`, `port` or `path`) and the
4893
+ * code that rule maps to (`host_forbidden` for the first three, `path_forbidden` for
4894
+ * `path`).
4895
+ */
4896
+ 403: {
4897
+ headers: {
4898
+ [name: string]: unknown;
4899
+ };
4900
+ content: {
4901
+ "application/json": {
4902
+ error: {
4903
+ /** @enum {string} */
4904
+ code: "url_forbidden";
4905
+ /** @example One or more URLs in this bulk request are blocked. */
4906
+ message: string;
4907
+ };
4908
+ blocked: {
4909
+ url: string;
4910
+ /** @enum {string} */
4911
+ rule_type: "domain" | "tld" | "port" | "path";
4912
+ /** @enum {string} */
4913
+ error_code: "host_forbidden" | "path_forbidden";
4914
+ }[];
4915
+ };
4916
+ };
4917
+ };
4460
4918
  /**
4461
4919
  * @description Validation error. `bulk_too_large` is returned when the item count
4462
4920
  * exceeds the account plan's `max_bulk_size` cap (also surfaced as
@@ -4674,6 +5132,7 @@ export interface operations {
4674
5132
  };
4675
5133
  };
4676
5134
  };
5135
+ 401: components["responses"]["Unauthorized"];
4677
5136
  /** @description Resource not found. */
4678
5137
  404: {
4679
5138
  headers: {
@@ -4735,6 +5194,7 @@ export interface operations {
4735
5194
  };
4736
5195
  };
4737
5196
  };
5197
+ 401: components["responses"]["Unauthorized"];
4738
5198
  /** @description Validation error. Returned when `status` is not one of the documented values, or when `cursor` is not a cursor this endpoint issued. */
4739
5199
  422: {
4740
5200
  headers: {
@@ -4829,7 +5289,7 @@ export interface operations {
4829
5289
  language?: string | null;
4830
5290
  dark_mode?: boolean;
4831
5291
  /** @description Scrape output formats (scrape entries). */
4832
- formats?: ("raw" | "markdown" | "links" | "images")[];
5292
+ formats?: (("raw" | "markdown" | "links" | "images") | components["schemas"]["ScrapeRequestJsonFormat"])[];
4833
5293
  /** @enum {string} */
4834
5294
  wait_until?: "load" | "domcontentloaded" | "networkidle";
4835
5295
  wait_for_selector?: string | null;
@@ -4882,7 +5342,7 @@ export interface operations {
4882
5342
  language?: string | null;
4883
5343
  /** @default false */
4884
5344
  dark_mode?: boolean;
4885
- formats?: ("raw" | "markdown" | "links" | "images")[];
5345
+ formats?: (("raw" | "markdown" | "links" | "images") | components["schemas"]["ScrapeRequestJsonFormat"])[];
4886
5346
  /**
4887
5347
  * @default load
4888
5348
  * @enum {string}
@@ -4970,7 +5430,38 @@ export interface operations {
4970
5430
  "application/json": components["schemas"]["Error"];
4971
5431
  };
4972
5432
  };
5433
+ 401: components["responses"]["Unauthorized"];
4973
5434
  402: components["responses"]["PaymentRequired"];
5435
+ /**
5436
+ * @description One or more URLs in the request are on ByteKit's blocklist. The whole request is
5437
+ * rejected before anything is queued or billed. This body is NOT the unified `Error`
5438
+ * envelope: it carries no `status`, `http_status` or `failed_at`. `blocked` lists every
5439
+ * offending URL with the rule that matched (`domain`, `tld`, `port` or `path`) and the
5440
+ * code that rule maps to (`host_forbidden` for the first three, `path_forbidden` for
5441
+ * `path`).
5442
+ */
5443
+ 403: {
5444
+ headers: {
5445
+ [name: string]: unknown;
5446
+ };
5447
+ content: {
5448
+ "application/json": {
5449
+ error: {
5450
+ /** @enum {string} */
5451
+ code: "url_forbidden";
5452
+ /** @example One or more URLs in this bulk request are blocked. */
5453
+ message: string;
5454
+ };
5455
+ blocked: {
5456
+ url: string;
5457
+ /** @enum {string} */
5458
+ rule_type: "domain" | "tld" | "port" | "path";
5459
+ /** @enum {string} */
5460
+ error_code: "host_forbidden" | "path_forbidden";
5461
+ }[];
5462
+ };
5463
+ };
5464
+ };
4974
5465
  /**
4975
5466
  * @description Validation error. `bulk_too_large` is returned when the item count
4976
5467
  * exceeds the account plan's `max_bulk_size` cap (also surfaced as
@@ -5076,6 +5567,7 @@ export interface operations {
5076
5567
  };
5077
5568
  };
5078
5569
  };
5570
+ 401: components["responses"]["Unauthorized"];
5079
5571
  /** @description Resource not found. */
5080
5572
  404: {
5081
5573
  headers: {
@@ -5130,6 +5622,7 @@ export interface operations {
5130
5622
  };
5131
5623
  };
5132
5624
  };
5625
+ 401: components["responses"]["Unauthorized"];
5133
5626
  /** @description Resource not found. */
5134
5627
  404: {
5135
5628
  headers: {
@@ -5223,10 +5716,14 @@ export interface operations {
5223
5716
  markdown?: string | null;
5224
5717
  /** @description `type: scrape` only. Pre-signed download URL for the markdown rendering of the page, valid for 600 seconds (10 minutes) from the moment this response was generated — the same signing TTL as `content_url` and `image_url` above. A new signature is minted on every poll for a completed item with a markdown key. For every other item the stored value is returned unchanged — `null` while no markdown has been stored, and otherwise a private, unsigned storage URL that returns 401 on download. No `artifact_warnings` entry is raised for this field; unlike `GET /v1/fetch/bulk/{id}`, this endpoint reports no `artifact_unavailable` when signing fails. */
5225
5718
  markdown_url?: string | null;
5226
- /** @description `type: scrape` only. Exact requested artifact values or signed references. Every key is present; unrequested or unavailable values are null, with nonfatal reference failures in `artifact_warnings`. */
5719
+ /** @description `type: scrape` only. Exact requested artifact values or signed references. `raw`, `markdown`, `links` and `images` are always present; unrequested or unavailable values are null, with nonfatal reference failures in `artifact_warnings`. `json` is present only on an item that requested a `json` format. */
5227
5720
  artifacts?: {
5228
5721
  raw: string | null;
5229
5722
  markdown: string | null;
5723
+ /** @description The item's `json` format result (`data`, `validated`, `model`); `null` while the item has stored none. */
5724
+ json?: {
5725
+ [key: string]: unknown;
5726
+ } | null;
5230
5727
  links: null | (string | components["schemas"]["ScrapeScoredLink"])[];
5231
5728
  images: null | (string | components["schemas"]["ScrapeScoredImage"])[];
5232
5729
  };
@@ -5251,6 +5748,7 @@ export interface operations {
5251
5748
  };
5252
5749
  };
5253
5750
  };
5751
+ 401: components["responses"]["Unauthorized"];
5254
5752
  };
5255
5753
  };
5256
5754
  listMonitors: {
@@ -5280,6 +5778,7 @@ export interface operations {
5280
5778
  };
5281
5779
  };
5282
5780
  };
5781
+ 401: components["responses"]["Unauthorized"];
5283
5782
  };
5284
5783
  };
5285
5784
  createMonitor: {
@@ -5324,6 +5823,7 @@ export interface operations {
5324
5823
  "application/json": components["schemas"]["Error"];
5325
5824
  };
5326
5825
  };
5826
+ 401: components["responses"]["Unauthorized"];
5327
5827
  /** @description Duplicate monitor for this URL. */
5328
5828
  409: {
5329
5829
  headers: {
@@ -5364,6 +5864,7 @@ export interface operations {
5364
5864
  "application/json": components["schemas"]["MonitorResponse"];
5365
5865
  };
5366
5866
  };
5867
+ 401: components["responses"]["Unauthorized"];
5367
5868
  /** @description Resource not found. */
5368
5869
  404: {
5369
5870
  headers: {
@@ -5393,6 +5894,7 @@ export interface operations {
5393
5894
  };
5394
5895
  content?: never;
5395
5896
  };
5897
+ 401: components["responses"]["Unauthorized"];
5396
5898
  /** @description Resource not found. */
5397
5899
  404: {
5398
5900
  headers: {
@@ -5448,6 +5950,7 @@ export interface operations {
5448
5950
  "application/json": components["schemas"]["Error"];
5449
5951
  };
5450
5952
  };
5953
+ 401: components["responses"]["Unauthorized"];
5451
5954
  /** @description Resource not found. */
5452
5955
  404: {
5453
5956
  headers: {
@@ -5505,6 +6008,7 @@ export interface operations {
5505
6008
  };
5506
6009
  };
5507
6010
  };
6011
+ 401: components["responses"]["Unauthorized"];
5508
6012
  };
5509
6013
  };
5510
6014
  createSitemap: {
@@ -5548,7 +6052,25 @@ export interface operations {
5548
6052
  "application/json": components["schemas"]["Error"];
5549
6053
  };
5550
6054
  };
6055
+ 401: components["responses"]["Unauthorized"];
5551
6056
  402: components["responses"]["PaymentRequired"];
6057
+ /**
6058
+ * @description The target is on ByteKit's blocklist. Nothing is queued and nothing is billed.
6059
+ * The unified `Error` envelope carries one of two codes:
6060
+ *
6061
+ * - `host_forbidden` — a blocked domain, any `.gov` host, or a blocked port.
6062
+ * `details` is `{ host }`.
6063
+ * - `path_forbidden` — an authentication-style path such as a login page.
6064
+ * `details` is `{ path }`.
6065
+ */
6066
+ 403: {
6067
+ headers: {
6068
+ [name: string]: unknown;
6069
+ };
6070
+ content: {
6071
+ "application/json": components["schemas"]["Error"];
6072
+ };
6073
+ };
5552
6074
  /** @description Validation error. */
5553
6075
  422: {
5554
6076
  headers: {
@@ -5597,6 +6119,7 @@ export interface operations {
5597
6119
  "application/json": components["schemas"]["SitemapResponse"];
5598
6120
  };
5599
6121
  };
6122
+ 401: components["responses"]["Unauthorized"];
5600
6123
  /** @description Resource not found. */
5601
6124
  404: {
5602
6125
  headers: {
@@ -5636,7 +6159,7 @@ export interface operations {
5636
6159
  * }
5637
6160
  */
5638
6161
  "application/json": {
5639
- /** @description The search query. */
6162
+ /** @description The search query, up to 2048 characters. */
5640
6163
  query: string;
5641
6164
  /**
5642
6165
  * @description Which search index to query. `web` (default) returns ranked organic results; `news` returns news articles in the same `results` array, additionally populating `source` and `image` on each item; `images` returns image results, populating `source`, `domain`, and a fuller `image` object (full-image dimensions plus a thumbnail URL and dimensions) while omitting `snippet` and `date`. Billing is identical for all three.
@@ -5753,6 +6276,7 @@ export interface operations {
5753
6276
  "application/json": components["schemas"]["Error"];
5754
6277
  };
5755
6278
  };
6279
+ 401: components["responses"]["Unauthorized"];
5756
6280
  402: components["responses"]["PaymentRequired"];
5757
6281
  /** @description Rate limit exceeded (`rate_limited`). Carries the `X-RateLimit-Limit`/`X-RateLimit-Remaining`/`X-RateLimit-Reset` triplet and a `Retry-After` header. The window is per-second for a bearer API key, or the 60-request/60-second Clerk session window when authenticated via `resolveDualAuth` — `Retry-After` reflects whichever window applies to the request. */
5758
6282
  429: {
@@ -5777,25 +6301,28 @@ export interface operations {
5777
6301
  };
5778
6302
  };
5779
6303
  /**
5780
- * @description Upstream search provider error, answered at `503` rather than `502` because
5781
- * Cloudflare replaces an origin 502 body with its own page (#4891). The body is a fixed,
5782
- * vendor-masked shape — deliberately NOT the unified `Error`
5783
- * envelope. The upstream provider's identity and message are
5784
- * never surfaced, so the response carries only the constant
5785
- * `error` code `search_provider_error`.
6304
+ * @description Two different bodies travel under this status. Tell them apart by the
6305
+ * type of the top-level `error` key: a string is the first, an object
6306
+ * is the second.
6307
+ *
6308
+ * - **Upstream search provider error**, answered at `503` rather than
6309
+ * `502` because Cloudflare replaces an origin 502 body with its own
6310
+ * page (#4891). The body is a fixed, vendor-masked shape —
6311
+ * deliberately NOT the unified `Error` envelope. The upstream
6312
+ * provider's identity and message are never surfaced, so the
6313
+ * response carries only the constant `error` code
6314
+ * `search_provider_error`.
6315
+ * - **Billing entitlement unavailable** (`billing_entitlement_missing`),
6316
+ * raised before any search runs, when the account has a Stripe
6317
+ * subscription but its plan could not be resolved. This one is the
6318
+ * unified `Error` envelope. No search is run and nothing is charged.
5786
6319
  */
5787
6320
  503: {
5788
6321
  headers: {
5789
6322
  [name: string]: unknown;
5790
6323
  };
5791
6324
  content: {
5792
- "application/json": {
5793
- /**
5794
- * @description Fixed vendor-masked error code. Always `search_provider_error`; the upstream provider's identity and failure detail are withheld by design.
5795
- * @enum {string}
5796
- */
5797
- error: "search_provider_error";
5798
- };
6325
+ "application/json": components["schemas"]["CreateSearchResponse503"] | components["schemas"]["Error"];
5799
6326
  };
5800
6327
  };
5801
6328
  };
@@ -5833,7 +6360,7 @@ export interface operations {
5833
6360
  * @description Target page URL (HTTP/HTTPS, SSRF-blocked, fast-path only).
5834
6361
  */
5835
6362
  url: string;
5836
- /** @description JSON Schema (draft 2020-12) describing the desired output. Serialized size ≤ 50 KB, nesting depth ≤ 8, must compile under Ajv, and must be normalizable into Groq's strict-mode subset (root `type: object`; no `pattern`/`format`/`if`/`then`/`else`/ top-level `oneOf`/`anyOf`; `$ref` limited to `#/$defs`). A non-normalizable schema returns `422 schema_incompatible`. */
6363
+ /** @description JSON Schema (draft 2020-12) describing the desired output. Serialized size ≤ 50 KB, nesting depth ≤ 8, must compile under Ajv, and must be normalizable into Groq's strict-mode subset: root `type: object`, and only an allowlist of keywords at any depth — `type`, `properties`, `required`, `additionalProperties`, `items`, `enum`, `$defs`, `$ref`, `description`, `title` and `default` (`$ref` limited to `#/$defs`). Every other keyword, such as `pattern`, `format`, `minimum`, `maxLength`, `const`, `oneOf`, `anyOf`, `allOf` or `if`/`then`/`else`, returns `422 schema_incompatible`. */
5837
6364
  schema: Record<string, never>;
5838
6365
  /** @description Optional natural-language extraction hint. */
5839
6366
  prompt?: string;
@@ -5857,7 +6384,10 @@ export interface operations {
5857
6384
  * @default US
5858
6385
  */
5859
6386
  country?: string | null;
5860
- /** @default null */
6387
+ /**
6388
+ * @description Accepted and forwarded to the extraction service, which does not read it: it currently has no effect.
6389
+ * @default null
6390
+ */
5861
6391
  language?: string | null;
5862
6392
  };
5863
6393
  };
@@ -5890,7 +6420,7 @@ export interface operations {
5890
6420
  status_code: number | null;
5891
6421
  /** @description Upstream wire bytes — the bandwidth billing basis. */
5892
6422
  content_length: number;
5893
- /** @description True when markdown exceeded the LLM token budget and was tail-truncated. */
6423
+ /** @description True when the page sent to the LLM, the structured metadata (JSON-LD and meta tags) plus the markdown, exceeded the token budget and was cut to fit. */
5894
6424
  truncated: boolean;
5895
6425
  };
5896
6426
  /** @description Additive warning codes, e.g. `content_truncated`, `extract_validation_failed`, `exhausted_retries`, `model_refusal`, `empty_extraction`. */
@@ -5907,8 +6437,15 @@ export interface operations {
5907
6437
  "application/json": components["schemas"]["Error"];
5908
6438
  };
5909
6439
  };
5910
- /** @description Missing or invalid bearer key. */
5911
- 401: {
6440
+ 401: components["responses"]["Unauthorized"];
6441
+ 402: components["responses"]["PaymentRequired"];
6442
+ /**
6443
+ * @description Validation error (`validation_error`), non-normalizable schema (`schema_incompatible`),
6444
+ * or the fetched page's HTML could not be converted for extraction — over the size cap or
6445
+ * past the conversion deadline (`content_too_large`). On `content_too_large` the page's
6446
+ * bandwidth is billed and the credits are refunded.
6447
+ */
6448
+ 422: {
5912
6449
  headers: {
5913
6450
  [name: string]: unknown;
5914
6451
  };
@@ -5916,9 +6453,8 @@ export interface operations {
5916
6453
  "application/json": components["schemas"]["Error"];
5917
6454
  };
5918
6455
  };
5919
- 402: components["responses"]["PaymentRequired"];
5920
- /** @description Validation error (`validation_error`) or non-normalizable schema (`schema_incompatible`). */
5921
- 422: {
6456
+ /** @description Per-account rate limit (`rate_limited`) or upstream provider rate limit (`provider_rate_limited`); a `Retry-After` header may be present. */
6457
+ 429: {
5922
6458
  headers: {
5923
6459
  [name: string]: unknown;
5924
6460
  };
@@ -5926,8 +6462,11 @@ export interface operations {
5926
6462
  "application/json": components["schemas"]["Error"];
5927
6463
  };
5928
6464
  };
5929
- /** @description Per-account rate limit (`rate_limited`) or upstream provider rate limit (`provider_rate_limited`); a `Retry-After` header may be present. */
5930
- 429: {
6465
+ /**
6466
+ * @description Internal error (`internal_error`): the request could not be recorded, or its
6467
+ * bandwidth charge could not be reserved. The credits held for it are refunded.
6468
+ */
6469
+ 500: {
5931
6470
  headers: {
5932
6471
  [name: string]: unknown;
5933
6472
  };
@@ -6029,6 +6568,7 @@ export interface operations {
6029
6568
  };
6030
6569
  };
6031
6570
  };
6571
+ 401: components["responses"]["Unauthorized"];
6032
6572
  };
6033
6573
  };
6034
6574
  getUsageDaily: {
@@ -6097,6 +6637,7 @@ export interface operations {
6097
6637
  };
6098
6638
  };
6099
6639
  };
6640
+ 401: components["responses"]["Unauthorized"];
6100
6641
  };
6101
6642
  };
6102
6643
  getUsageByEndpoint: {
@@ -6144,6 +6685,7 @@ export interface operations {
6144
6685
  };
6145
6686
  };
6146
6687
  };
6688
+ 401: components["responses"]["Unauthorized"];
6147
6689
  };
6148
6690
  };
6149
6691
  getLogs: {
@@ -6227,6 +6769,7 @@ export interface operations {
6227
6769
  };
6228
6770
  };
6229
6771
  };
6772
+ 401: components["responses"]["Unauthorized"];
6230
6773
  };
6231
6774
  };
6232
6775
  createCheckout: {
@@ -6241,23 +6784,23 @@ export interface operations {
6241
6784
  "application/json": {
6242
6785
  /** @enum {string} */
6243
6786
  plan: "starter" | "growth" | "scale";
6244
- /** Format: uri */
6245
- success_url: string;
6246
- /** Format: uri */
6247
- cancel_url: string;
6787
+ /**
6788
+ * Format: uri
6789
+ * @description Where Stripe sends the user back if their bank requires leaving the page to authenticate the payment.
6790
+ */
6791
+ return_url: string;
6248
6792
  };
6249
6793
  };
6250
6794
  };
6251
6795
  responses: {
6252
- /** @description Successful response. */
6796
+ /** @description Checkout session created; pay it in-page with its client secret. */
6253
6797
  200: {
6254
6798
  headers: {
6255
6799
  [name: string]: unknown;
6256
6800
  };
6257
6801
  content: {
6258
6802
  "application/json": {
6259
- /** Format: uri */
6260
- checkout_url: string;
6803
+ client_secret: string;
6261
6804
  session_id: string;
6262
6805
  };
6263
6806
  };
@@ -6271,9 +6814,52 @@ export interface operations {
6271
6814
  "application/json": components["schemas"]["Error"];
6272
6815
  };
6273
6816
  };
6817
+ 401: components["responses"]["Unauthorized"];
6274
6818
  };
6275
6819
  };
6276
6820
  createPortal: {
6821
+ parameters: {
6822
+ query?: never;
6823
+ header?: never;
6824
+ path?: never;
6825
+ cookie?: never;
6826
+ };
6827
+ requestBody?: never;
6828
+ responses: {
6829
+ 401: components["responses"]["Unauthorized"];
6830
+ /** @description The portal is retired; manage billing at /settings/billing. */
6831
+ 410: {
6832
+ headers: {
6833
+ [name: string]: unknown;
6834
+ };
6835
+ content: {
6836
+ "application/json": components["schemas"]["Error"];
6837
+ };
6838
+ };
6839
+ };
6840
+ };
6841
+ registerPayg: {
6842
+ parameters: {
6843
+ query?: never;
6844
+ header?: never;
6845
+ path?: never;
6846
+ cookie?: never;
6847
+ };
6848
+ requestBody?: never;
6849
+ responses: {
6850
+ 401: components["responses"]["Unauthorized"];
6851
+ /** @description Card setup moved to POST /v1/billing/payment-methods/setup. */
6852
+ 410: {
6853
+ headers: {
6854
+ [name: string]: unknown;
6855
+ };
6856
+ content: {
6857
+ "application/json": components["schemas"]["Error"];
6858
+ };
6859
+ };
6860
+ };
6861
+ };
6862
+ createTopup: {
6277
6863
  parameters: {
6278
6864
  query?: never;
6279
6865
  header?: never;
@@ -6283,27 +6869,33 @@ export interface operations {
6283
6869
  requestBody: {
6284
6870
  content: {
6285
6871
  "application/json": {
6286
- /** @enum {string} */
6287
- purpose: "payment_method_update" | "invoice_history" | "subscription_cancel";
6288
- /** Format: uri */
6872
+ /**
6873
+ * @description Amount to deposit, in US cents. Allowed amounts — $10, $25, $50, $100, $500. Charged exactly; the plan rate prices usage, not the deposit.
6874
+ * @enum {integer}
6875
+ */
6876
+ amount_cents: 1000 | 2500 | 5000 | 10000 | 50000;
6877
+ /**
6878
+ * Format: uri
6879
+ * @description Where Stripe sends the user back if their bank requires leaving the page to authenticate the payment.
6880
+ */
6289
6881
  return_url: string;
6290
6882
  };
6291
6883
  };
6292
6884
  };
6293
6885
  responses: {
6294
- /** @description Successful response. */
6886
+ /** @description Checkout session created; pay it in-page with its client secret. */
6295
6887
  200: {
6296
6888
  headers: {
6297
6889
  [name: string]: unknown;
6298
6890
  };
6299
6891
  content: {
6300
6892
  "application/json": {
6301
- /** Format: uri */
6302
- portal_url: string;
6893
+ client_secret: string;
6894
+ session_id: string;
6303
6895
  };
6304
6896
  };
6305
6897
  };
6306
- /** @description No Stripe customer linked. */
6898
+ /** @description No customer or free plan. */
6307
6899
  400: {
6308
6900
  headers: {
6309
6901
  [name: string]: unknown;
@@ -6312,8 +6904,18 @@ export interface operations {
6312
6904
  "application/json": components["schemas"]["Error"];
6313
6905
  };
6314
6906
  };
6315
- /** @description Cancellation disclosure revision is absent or stale. */
6316
- 409: {
6907
+ 401: components["responses"]["Unauthorized"];
6908
+ /** @description Validation error (missing/invalid fields). */
6909
+ 422: {
6910
+ headers: {
6911
+ [name: string]: unknown;
6912
+ };
6913
+ content: {
6914
+ "application/json": components["schemas"]["Error"];
6915
+ };
6916
+ };
6917
+ /** @description Stripe error creating the Checkout session (`stripe_error`). Answered at `503`, not `502`, because Cloudflare replaces an origin 502 body with its own page (#4891). */
6918
+ 503: {
6317
6919
  headers: {
6318
6920
  [name: string]: unknown;
6319
6921
  };
@@ -6323,21 +6925,14 @@ export interface operations {
6323
6925
  };
6324
6926
  };
6325
6927
  };
6326
- registerPayg: {
6928
+ getCancellation: {
6327
6929
  parameters: {
6328
6930
  query?: never;
6329
6931
  header?: never;
6330
6932
  path?: never;
6331
6933
  cookie?: never;
6332
6934
  };
6333
- requestBody: {
6334
- content: {
6335
- "application/json": {
6336
- /** Format: uri */
6337
- return_url: string;
6338
- };
6339
- };
6340
- };
6935
+ requestBody?: never;
6341
6936
  responses: {
6342
6937
  /** @description Successful response. */
6343
6938
  200: {
@@ -6346,13 +6941,17 @@ export interface operations {
6346
6941
  };
6347
6942
  content: {
6348
6943
  "application/json": {
6349
- /** Format: uri */
6350
- checkout_url: string;
6351
- session_id: string;
6944
+ /** @description Whether the plan ends at the period end instead of renewing. */
6945
+ cancel_at_period_end: boolean;
6946
+ /**
6947
+ * Format: date-time
6948
+ * @description When the paid period ends, read from the plan's subscription item.
6949
+ */
6950
+ current_period_end: string | null;
6352
6951
  };
6353
6952
  };
6354
6953
  };
6355
- /** @description Already registered. */
6954
+ /** @description No subscription (`no_subscription`). */
6356
6955
  400: {
6357
6956
  headers: {
6358
6957
  [name: string]: unknown;
@@ -6361,51 +6960,54 @@ export interface operations {
6361
6960
  "application/json": components["schemas"]["Error"];
6362
6961
  };
6363
6962
  };
6963
+ 401: components["responses"]["Unauthorized"];
6964
+ /** @description The caller is not an account admin (`forbidden`). */
6965
+ 403: {
6966
+ headers: {
6967
+ [name: string]: unknown;
6968
+ };
6969
+ content: {
6970
+ "application/json": components["schemas"]["Error"];
6971
+ };
6972
+ };
6973
+ /** @description The Stripe subscription could not be read (`stripe_error`). Answered at `503`, not `502`, because Cloudflare replaces an origin 502 body with its own page (#4891). */
6974
+ 503: {
6975
+ headers: {
6976
+ [name: string]: unknown;
6977
+ };
6978
+ content: {
6979
+ "application/json": components["schemas"]["Error"];
6980
+ };
6981
+ };
6364
6982
  };
6365
6983
  };
6366
- createTopup: {
6984
+ cancelSubscription: {
6367
6985
  parameters: {
6368
6986
  query?: never;
6369
6987
  header?: never;
6370
6988
  path?: never;
6371
6989
  cookie?: never;
6372
6990
  };
6373
- requestBody: {
6374
- content: {
6375
- "application/json": {
6376
- /**
6377
- * @description Amount to deposit, in US cents. Allowed amounts — $10, $25, $50, $100, $500. Charged exactly; the plan rate prices usage, not the deposit.
6378
- * @enum {integer}
6379
- */
6380
- amount_cents: 1000 | 2500 | 5000 | 10000 | 50000;
6381
- /**
6382
- * Format: uri
6383
- * @description Redirect target after a completed Checkout.
6384
- */
6385
- success_url: string;
6386
- /**
6387
- * Format: uri
6388
- * @description Redirect target when the user abandons Checkout.
6389
- */
6390
- cancel_url: string;
6391
- };
6392
- };
6393
- };
6991
+ requestBody?: never;
6394
6992
  responses: {
6395
- /** @description Hosted Checkout session created. */
6993
+ /** @description The plan now ends at the period end. */
6396
6994
  200: {
6397
6995
  headers: {
6398
6996
  [name: string]: unknown;
6399
6997
  };
6400
6998
  content: {
6401
6999
  "application/json": {
6402
- /** Format: uri */
6403
- checkout_url: string;
6404
- session_id: string;
7000
+ /** @description Whether the plan ends at the period end instead of renewing. */
7001
+ cancel_at_period_end: boolean;
7002
+ /**
7003
+ * Format: date-time
7004
+ * @description When the paid period ends, read from the plan's subscription item.
7005
+ */
7006
+ current_period_end: string | null;
6405
7007
  };
6406
7008
  };
6407
7009
  };
6408
- /** @description No customer or free plan. */
7010
+ /** @description No subscription (`no_subscription`). */
6409
7011
  400: {
6410
7012
  headers: {
6411
7013
  [name: string]: unknown;
@@ -6414,8 +7016,9 @@ export interface operations {
6414
7016
  "application/json": components["schemas"]["Error"];
6415
7017
  };
6416
7018
  };
6417
- /** @description Validation error (missing/invalid fields). */
6418
- 422: {
7019
+ 401: components["responses"]["Unauthorized"];
7020
+ /** @description The caller is not an account admin (`forbidden`). */
7021
+ 403: {
6419
7022
  headers: {
6420
7023
  [name: string]: unknown;
6421
7024
  };
@@ -6423,7 +7026,16 @@ export interface operations {
6423
7026
  "application/json": components["schemas"]["Error"];
6424
7027
  };
6425
7028
  };
6426
- /** @description Stripe error creating the Checkout session (`stripe_error`). Answered at `503`, not `502`, because Cloudflare replaces an origin 502 body with its own page (#4891). */
7029
+ /** @description Cancellation disclosure revision is absent or stale (`billing_disclosure_stale`). The current revision is in the `Billing-Disclosure-Revision` response header. */
7030
+ 409: {
7031
+ headers: {
7032
+ [name: string]: unknown;
7033
+ };
7034
+ content: {
7035
+ "application/json": components["schemas"]["Error"];
7036
+ };
7037
+ };
7038
+ /** @description Stripe refused or failed the cancellation (`stripe_error`). Answered at `503`, not `502`, because Cloudflare replaces an origin 502 body with its own page (#4891). */
6427
7039
  503: {
6428
7040
  headers: {
6429
7041
  [name: string]: unknown;
@@ -6434,23 +7046,53 @@ export interface operations {
6434
7046
  };
6435
7047
  };
6436
7048
  };
6437
- cancelSubscription: {
7049
+ keepSubscription: {
6438
7050
  parameters: {
6439
7051
  query?: never;
6440
7052
  header?: never;
6441
7053
  path?: never;
6442
7054
  cookie?: never;
6443
7055
  };
6444
- requestBody: {
6445
- content: {
6446
- "application/json": {
6447
- reason?: string;
7056
+ requestBody?: never;
7057
+ responses: {
7058
+ /** @description The plan renews at the period end. */
7059
+ 200: {
7060
+ headers: {
7061
+ [name: string]: unknown;
7062
+ };
7063
+ content: {
7064
+ "application/json": {
7065
+ /** @description Whether the plan ends at the period end instead of renewing. */
7066
+ cancel_at_period_end: boolean;
7067
+ /**
7068
+ * Format: date-time
7069
+ * @description When the paid period ends, read from the plan's subscription item.
7070
+ */
7071
+ current_period_end: string | null;
7072
+ };
6448
7073
  };
6449
7074
  };
6450
- };
6451
- responses: {
6452
- /** @description Cancellation moved to hosted Billing Portal. */
6453
- 410: {
7075
+ /** @description No subscription (`no_subscription`). */
7076
+ 400: {
7077
+ headers: {
7078
+ [name: string]: unknown;
7079
+ };
7080
+ content: {
7081
+ "application/json": components["schemas"]["Error"];
7082
+ };
7083
+ };
7084
+ 401: components["responses"]["Unauthorized"];
7085
+ /** @description The caller is not an account admin (`forbidden`). */
7086
+ 403: {
7087
+ headers: {
7088
+ [name: string]: unknown;
7089
+ };
7090
+ content: {
7091
+ "application/json": components["schemas"]["Error"];
7092
+ };
7093
+ };
7094
+ /** @description Stripe refused or failed the change (`stripe_error`). Answered at `503`, not `502`, because Cloudflare replaces an origin 502 body with its own page (#4891). */
7095
+ 503: {
6454
7096
  headers: {
6455
7097
  [name: string]: unknown;
6456
7098
  };
@@ -6495,6 +7137,7 @@ export interface operations {
6495
7137
  "application/json": components["schemas"]["Error"];
6496
7138
  };
6497
7139
  };
7140
+ 401: components["responses"]["Unauthorized"];
6498
7141
  /** @description The Stripe subscription schedule could not be read (`stripe_error`). Answered at `503`, not `502`, because Cloudflare replaces an origin 502 body with its own page (#4891). */
6499
7142
  503: {
6500
7143
  headers: {
@@ -6555,6 +7198,7 @@ export interface operations {
6555
7198
  "application/json": components["schemas"]["Error"];
6556
7199
  };
6557
7200
  };
7201
+ 401: components["responses"]["Unauthorized"];
6558
7202
  };
6559
7203
  };
6560
7204
  revokePlanChange: {
@@ -6589,6 +7233,7 @@ export interface operations {
6589
7233
  "application/json": components["schemas"]["Error"];
6590
7234
  };
6591
7235
  };
7236
+ 401: components["responses"]["Unauthorized"];
6592
7237
  };
6593
7238
  };
6594
7239
  listInvoices: {
@@ -6623,6 +7268,7 @@ export interface operations {
6623
7268
  invoice_pdf: string | null;
6624
7269
  hosted_invoice_url: string | null;
6625
7270
  }[];
7271
+ /** @description True when older invoices exist after this page. */
6626
7272
  has_more: boolean;
6627
7273
  };
6628
7274
  };
@@ -6636,6 +7282,7 @@ export interface operations {
6636
7282
  "application/json": components["schemas"]["Error"];
6637
7283
  };
6638
7284
  };
7285
+ 401: components["responses"]["Unauthorized"];
6639
7286
  };
6640
7287
  };
6641
7288
  getTopupBalance: {
@@ -6691,6 +7338,7 @@ export interface operations {
6691
7338
  };
6692
7339
  };
6693
7340
  };
7341
+ 401: components["responses"]["Unauthorized"];
6694
7342
  };
6695
7343
  };
6696
7344
  updateAutoTopup: {
@@ -6737,6 +7385,7 @@ export interface operations {
6737
7385
  "application/json": components["schemas"]["Error"];
6738
7386
  };
6739
7387
  };
7388
+ 401: components["responses"]["Unauthorized"];
6740
7389
  };
6741
7390
  };
6742
7391
  createPaymentMethodSetup: {
@@ -6766,6 +7415,7 @@ export interface operations {
6766
7415
  "application/json": components["schemas"]["Error"];
6767
7416
  };
6768
7417
  };
7418
+ 401: components["responses"]["Unauthorized"];
6769
7419
  };
6770
7420
  };
6771
7421
  listPaymentMethods: {
@@ -6797,6 +7447,7 @@ export interface operations {
6797
7447
  "application/json": components["schemas"]["Error"];
6798
7448
  };
6799
7449
  };
7450
+ 401: components["responses"]["Unauthorized"];
6800
7451
  };
6801
7452
  };
6802
7453
  setDefaultPaymentMethod: {
@@ -6828,6 +7479,7 @@ export interface operations {
6828
7479
  "application/json": components["schemas"]["Error"];
6829
7480
  };
6830
7481
  };
7482
+ 401: components["responses"]["Unauthorized"];
6831
7483
  /** @description Payment method not found. */
6832
7484
  404: {
6833
7485
  headers: {
@@ -6877,6 +7529,7 @@ export interface operations {
6877
7529
  "application/json": components["schemas"]["Error"];
6878
7530
  };
6879
7531
  };
7532
+ 401: components["responses"]["Unauthorized"];
6880
7533
  /** @description Payment method not found. */
6881
7534
  404: {
6882
7535
  headers: {
@@ -6972,6 +7625,7 @@ export interface operations {
6972
7625
  };
6973
7626
  };
6974
7627
  };
7628
+ 401: components["responses"]["Unauthorized"];
6975
7629
  };
6976
7630
  };
6977
7631
  retryWebhookDelivery: {
@@ -7006,6 +7660,7 @@ export interface operations {
7006
7660
  "application/json": components["schemas"]["Error"];
7007
7661
  };
7008
7662
  };
7663
+ 401: components["responses"]["Unauthorized"];
7009
7664
  /** @description Delivery not found or not in a retryable state. */
7010
7665
  404: {
7011
7666
  headers: {
@@ -7117,7 +7772,7 @@ export interface operations {
7117
7772
  "application/json": components["schemas"]["Account"];
7118
7773
  };
7119
7774
  };
7120
- /** @description Account created. */
7775
+ /** @description First successful bootstrap: the caller joined a pending invite's account, or a new account was created. */
7121
7776
  201: {
7122
7777
  headers: {
7123
7778
  [name: string]: unknown;