@hunt-labs/bytekit-sdk 0.9.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -194,7 +194,17 @@ export interface paths {
194
194
  put?: never;
195
195
  /**
196
196
  * Scrape a URL
197
- * @description Fetches and processes a URL, returning content in one or more formats wrapped in a ScrapeEnvelope. Most requests return synchronously in under a second; requests needing a full page render return HTTP 202 and complete asynchronously.
197
+ * @description Fetches and processes a URL, returning content in one or more formats wrapped in a ScrapeEnvelope.
198
+ *
199
+ * **The response shape is decided by your request, not by how we route it.** In precedence order:
200
+ *
201
+ * 1. `async: true` → **202** with a `ScrapeQueuedEnvelope` receipt, returned immediately. Poll `GET /v1/scrape/{id}` for the result.
202
+ * 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
+ * 3. Otherwise the request is served by the fast HTTP path and returns **200** with the content envelope, typically in under a second.
204
+ *
205
+ * **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 happens before any job row exists, so its envelope carries `id: 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
+ *
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.
198
208
  */
199
209
  post: operations["createScrape"];
200
210
  delete?: never;
@@ -235,9 +245,10 @@ export interface paths {
235
245
  /**
236
246
  * Bulk scrape URLs
237
247
  * @description Enqueues multiple URLs for scraping. Results delivered via webhook.
238
- * Webhook deliveries include `X-ByteKit-Event: scrape.completed` or
239
- * `X-ByteKit-Event: scrape.failed` so receivers can dispatch on the
240
- * header without parsing the body shape.
248
+ * Completion deliveries use `X-ByteKit-Event: bulk.completed` and the
249
+ * `BulkCompletedWebhook` contract: at most 500 complete items and 1 MiB,
250
+ * followed by cursor recovery through `GET /v1/scrape/bulk/{id}` whenever
251
+ * `recovery_required` is true.
241
252
  */
242
253
  post: operations["createScrapeBulk"];
243
254
  delete?: never;
@@ -253,7 +264,20 @@ export interface paths {
253
264
  path?: never;
254
265
  cookie?: never;
255
266
  };
256
- /** Get scrape bulk job status */
267
+ /**
268
+ * Get scrape bulk job status
269
+ * @description Returns the job envelope plus its rehydrated per-URL scrape envelopes.
270
+ *
271
+ * **Downloading item content.** A `raw` or `markdown` artifact within the
272
+ * 10-MiB inline cap is returned inline. An oversized one is replaced by a
273
+ * **pre-signed** URL, minted fresh on every read of this endpoint and valid
274
+ * for **86400 seconds (24 hours)**. The underlying objects are private, so an
275
+ * unsigned URL returns `401`: download the content inside that window, or
276
+ * re-poll this endpoint for a fresh signature. An artifact that was never
277
+ * stored, or whose object cannot be signed, is omitted from `formats` and
278
+ * reported as `artifact_unavailable` in `warnings`. The private unsigned
279
+ * storage URL is never returned.
280
+ */
257
281
  get: operations["getScrapeBulk"];
258
282
  put?: never;
259
283
  post?: never;
@@ -305,6 +329,10 @@ export interface paths {
305
329
  * Bulk fetch URLs
306
330
  * @description Enqueues multiple URLs for HTTP fetching. Results delivered via webhook.
307
331
  * Does not support options that require page rendering (wait_for_selector, etc.).
332
+ * Completion deliveries use `X-ByteKit-Event: bulk.completed` and the
333
+ * `BulkCompletedWebhook` contract: at most 500 complete items and 1 MiB,
334
+ * followed by cursor recovery through `GET /v1/fetch/bulk/{id}` whenever
335
+ * `recovery_required` is true.
308
336
  *
309
337
  * **Limits:** request bodies are guarded in a two-tier shape. A streamed body
310
338
  * with no `Content-Length` header is capped at 2 MB before your API key
@@ -342,7 +370,9 @@ export interface paths {
342
370
  * objects are private, so an unsigned URL returns `401`: download the
343
371
  * content inside that window, or re-poll this endpoint for a fresh
344
372
  * signature. Items that are not `completed`, and completed items with no
345
- * stored object, carry `null` or the unsigned stored URL instead.
373
+ * stored object, or completed items whose object cannot be signed, carry
374
+ * `null`; the latter report `artifact_unavailable`. The private unsigned
375
+ * storage URL is never returned.
346
376
  */
347
377
  get: operations["getFetchBulk"];
348
378
  put?: never;
@@ -373,6 +403,9 @@ export interface paths {
373
403
  * Provide `urls` (simple list) or `items` (per-item config), not both.
374
404
  * Webhook deliveries include `X-ByteKit-Event: bulk.completed` so
375
405
  * receivers can dispatch on the header without parsing the body shape.
406
+ * The body follows `BulkCompletedWebhook`: at most 500 complete items and
407
+ * 1 MiB, followed by cursor recovery through the existing mixed-item route
408
+ * whenever `recovery_required` is true.
376
409
  *
377
410
  * **Limits:** request bodies are guarded in a two-tier shape. A streamed body
378
411
  * with no `Content-Length` header is capped at 4 MB before your API key
@@ -424,15 +457,25 @@ export interface paths {
424
457
  * List bulk job items
425
458
  * @description Returns the bulk job's items, discriminated by `type`.
426
459
  *
427
- * **Downloading item artifacts.** `image_url` (`type: screenshot`) and both
428
- * `content_url` and `markdown_url` (`type: scrape`) are **pre-signed** URLs,
429
- * minted fresh on every read of this endpoint and valid for **600 seconds
430
- * (10 minutes)** —
460
+ * **Downloading item artifacts.** For a `completed` item with a storage key,
461
+ * `image_url` (`type: screenshot`) and both `content_url` and `markdown_url`
462
+ * (`type: scrape`) are **pre-signed** URLs, minted fresh on every read of
463
+ * this endpoint and valid for **600 seconds (10 minutes)** —
431
464
  * the same signing lifetime as `content_url` on `GET /v1/fetch/bulk/{id}`.
432
- * The underlying objects are private, so an unsigned URL returns `401`:
433
- * download inside that window, or re-poll this endpoint for a fresh
434
- * signature. Items that are not `completed`, and completed items with no
435
- * stored object, carry `null` or the unsigned stored URL instead.
465
+ * Download inside that window, or re-poll this endpoint for a fresh
466
+ * signature.
467
+ *
468
+ * **When no signature is minted.** Three cases mint none: an item that is not
469
+ * `completed`, a `completed` item with no storage key, and a `completed` item
470
+ * whose object could not be signed — during an object-storage outage, for
471
+ * instance. In all three the item's stored value is returned unchanged: `null`
472
+ * while nothing has been stored, and otherwise a **private, unsigned**
473
+ * object-storage URL that answers `401`. These fields are neither nulled nor
474
+ * flagged in that case, so treat an artifact URL as usable only once you have
475
+ * downloaded it, and re-poll for a fresh signature otherwise.
476
+ * `artifact_warnings` and its `artifact_unavailable` code describe the sibling
477
+ * `artifacts` object on `type: scrape` items only — they say nothing about
478
+ * `image_url`, `content_url`, or `markdown_url`.
436
479
  */
437
480
  get: operations["listBulkScreenshots"];
438
481
  put?: never;
@@ -816,11 +859,19 @@ export interface paths {
816
859
  path?: never;
817
860
  cookie?: never;
818
861
  };
819
- get?: never;
862
+ /**
863
+ * Read a scheduled plan change
864
+ * @description The plan change booked for the end of the current period, if any, reconstructed from the Stripe subscription schedule on each call. Both fields are null when nothing is booked, including while the schedule stays attached for one further interval after a change has already landed.
865
+ */
866
+ get: operations["getPlanChange"];
820
867
  put?: never;
821
868
  /** Change subscription plan */
822
869
  post: operations["changePlan"];
823
- delete?: never;
870
+ /**
871
+ * Revoke a scheduled plan change
872
+ * @description Cancels a plan change booked for the end of the current period. The subscription simply renews on the plan it is already on.
873
+ */
874
+ delete: operations["revokePlanChange"];
824
875
  options?: never;
825
876
  head?: never;
826
877
  patch?: never;
@@ -874,7 +925,8 @@ export interface paths {
874
925
  /**
875
926
  * Configure auto-topup
876
927
  * @description Enable or disable automatic bandwidth top-ups. When enabling,
877
- * threshold_bytes, amount_bytes, and monthly_cap_cents are all required.
928
+ * threshold_bytes, amount_bytes, and monthly_cap_cents must all be present;
929
+ * monthly_cap_cents may be null, which means no monthly cap.
878
930
  */
879
931
  put: operations["updateAutoTopup"];
880
932
  post?: never;
@@ -1343,13 +1395,13 @@ export interface components {
1343
1395
  name: string;
1344
1396
  /**
1345
1397
  * @description Monthly subscription price in cents.
1346
- * @example 49900
1398
+ * @example 34900
1347
1399
  */
1348
1400
  price_cents: number;
1349
1401
  /**
1350
1402
  * Format: int64
1351
- * @description Included bandwidth per period, in bytes (binary GiB).
1352
- * @example 100000000000
1403
+ * @description Included bandwidth per period, in bytes (decimal GB = 1,000,000,000 bytes).
1404
+ * @example 125000000000
1353
1405
  */
1354
1406
  included_bytes: number;
1355
1407
  /**
@@ -1359,7 +1411,7 @@ export interface components {
1359
1411
  included_credits: number;
1360
1412
  /**
1361
1413
  * @description Bandwidth top-up price per MB, in cents.
1362
- * @example 0.25
1414
+ * @example 0.2
1363
1415
  */
1364
1416
  topup_price_per_mb_cents: number;
1365
1417
  /**
@@ -1405,6 +1457,95 @@ export interface components {
1405
1457
  details?: unknown;
1406
1458
  };
1407
1459
  };
1460
+ /**
1461
+ * @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`.
1462
+ *
1463
+ * REFERENCE DOCUMENTATION ONLY (#4340). No operation `$ref`s this schema and no response ever carries an object of this shape, so no client model is generated from it and no SDK re-exports it. On the wire the value appears as the FLAT `error_code` / `error_message` fields on a bulk list item — `GET /v1/fetch/bulk/{id}`, `GET /v1/bulk/{id}/screenshots` — and on the `items[]` entries of the `bulk.completed` webhook body, never as a nested `{ code, message }` object. This schema names the `artifact_unavailable` code and the contract that goes with it; the two properties below describe that code and message, not a wire envelope.
1464
+ */
1465
+ BulkArtifactUnavailableError: {
1466
+ /** @enum {string} */
1467
+ code: "artifact_unavailable";
1468
+ message: string;
1469
+ };
1470
+ /** @description Mandatory bounded scrape record emitted when the ordinary rehydrated envelope cannot fit within the 16-MiB page bound. The stable item identity and terminal outcome always remain available; bounded signed references and failure detail are included when they fit. */
1471
+ BulkMandatoryScrapeItem: {
1472
+ id: string;
1473
+ /** @enum {string} */
1474
+ type: "scrape";
1475
+ /** @enum {string} */
1476
+ terminal_outcome: "pending" | "processing" | "completed" | "failed" | "cancelled";
1477
+ /** Format: uri */
1478
+ url: string;
1479
+ /** @description Bounded signed references retained from the ordinary scrape envelope. Only the formats the job requested are present; the key set is the `/v1/scrape` format vocabulary. */
1480
+ formats?: {
1481
+ raw?: string | null;
1482
+ markdown?: string | null;
1483
+ links?: null | (string | components["schemas"]["ScrapeScoredLink"])[];
1484
+ images?: null | (string | components["schemas"]["ScrapeScoredImage"])[];
1485
+ };
1486
+ error?: {
1487
+ code: string;
1488
+ message: string | null;
1489
+ /** Format: date-time */
1490
+ failed_at: string | null;
1491
+ };
1492
+ };
1493
+ /** @description Whole-job counters. These do not reset or shrink with the current page. */
1494
+ BulkJobCounters: {
1495
+ total: number;
1496
+ completed: number;
1497
+ failed: number;
1498
+ };
1499
+ /**
1500
+ * @description Customer body for `X-ByteKit-Event: bulk.completed`. Delivery is bounded to
1501
+ * 500 complete items and 1 MiB of customer-visible JSON, stopping only between
1502
+ * items. When either item coverage or artifact coverage is incomplete, follow
1503
+ * `recovery_url` with cursor pagination; stable `bulk_id` plus each item `id`
1504
+ * supports idempotent processing after duplicate, delayed, or retried delivery.
1505
+ */
1506
+ BulkCompletedWebhook: {
1507
+ bulk_id: string;
1508
+ /** @enum {string} */
1509
+ status: "completed";
1510
+ total: number;
1511
+ completed: number;
1512
+ failed: number;
1513
+ total_credits_charged: number;
1514
+ /** Format: uri */
1515
+ webhook_url: string;
1516
+ /** @description Complete item records included before the 500-item or 1-MiB manifest bound. Every record carries a stable `id`, a `type`, and a terminal `status`. */
1517
+ items: ({
1518
+ /** @description Stable prefixed item id; deduplicate with `bulk_id` plus this id. */
1519
+ id: string;
1520
+ /** @enum {string} */
1521
+ type: "fetch" | "scrape" | "screenshot" | "recording";
1522
+ /** @enum {string} */
1523
+ status: "success" | "completed" | "failed" | "cancelled";
1524
+ /** @description May be `artifact_unavailable` when no usable result reference exists. */
1525
+ error_code?: string | null;
1526
+ error_message?: string | null;
1527
+ /** @description Present and true when the manifest bounded a long error message. */
1528
+ error_message_truncated?: boolean;
1529
+ } & {
1530
+ [key: string]: unknown;
1531
+ })[];
1532
+ /** @enum {string} */
1533
+ recovery_api: "fetch" | "scrape" | "mixed";
1534
+ /**
1535
+ * @description Existing paginated result-recovery path for this job.
1536
+ * @example /v1/fetch/bulk/bulk_01j9abc123
1537
+ */
1538
+ recovery_url: string;
1539
+ manifest_item_count: number;
1540
+ /** @description True when every terminal job item is present in this webhook body. */
1541
+ manifest_items_complete: boolean;
1542
+ /** @description True when every included completed item has a usable artifact or reference. */
1543
+ manifest_artifacts_complete: boolean;
1544
+ /** @description True only when both item and artifact coverage are complete. */
1545
+ manifest_complete: boolean;
1546
+ /** @description Inverse of `manifest_complete`; follow `recovery_url` when true. */
1547
+ recovery_required: boolean;
1548
+ };
1408
1549
  Viewport: {
1409
1550
  width: number;
1410
1551
  height: number;
@@ -1527,11 +1668,17 @@ export interface components {
1527
1668
  formats: ("raw" | "markdown" | "links" | "images")[];
1528
1669
  /** @default US */
1529
1670
  country: string;
1530
- /** @default 0 */
1671
+ /**
1672
+ * @description Milliseconds to wait after page load before capturing, for content that renders late. Any value above 0 puts the request on the full browser render path. Unless `async: true` is also set, the request is then HELD until the render finishes and returns 200 with the content envelope, or returns the 202 receipt if the hold window expires first. `0` (the default) keeps the request on the fast HTTP path, which returns 200 in one round trip.
1673
+ * @default 0
1674
+ */
1531
1675
  delay_ms: number;
1532
1676
  /** @default 30000 */
1533
1677
  timeout_ms: number;
1534
- /** @default false */
1678
+ /**
1679
+ * @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.
1680
+ * @default false
1681
+ */
1535
1682
  async: boolean;
1536
1683
  /**
1537
1684
  * Format: uri
@@ -1821,17 +1968,19 @@ export interface components {
1821
1968
  * from a prior cache entry (billed at 0.5×). `miss` — no reusable entry was
1822
1969
  * found, so the result was freshly fetched. `bypass` — `cache_ttl: '0'`
1823
1970
  * skipped the read. Cache-eligible fresh results are written through;
1824
- * safety-classified WAF husks remain live-only. Present on the async success
1825
- * envelope (synchronous and webhook delivery); omitted by paths with no cache
1826
- * verdict (e.g. bulk results).
1971
+ * safety-classified WAF husks remain live-only. Present on the synchronous
1972
+ * response, on webhook delivery, and on `GET /v1/scrape/{id}` for a row whose
1973
+ * terminal write recorded a disposition; omitted by paths with no cache verdict
1974
+ * (e.g. bulk results) and for a stored row that recorded none, where absent
1975
+ * means unknown rather than `miss`.
1827
1976
  * @enum {string}
1828
1977
  */
1829
1978
  cache?: "miss" | "hit" | "bypass";
1830
- /** @description Age in whole seconds of the cache entry replayed on a `hit`. Clamped to ≥ 0 to absorb clock skew. Present only on `cache: hit`. */
1979
+ /** @description Age in whole seconds of the cache entry replayed on a `hit`. Clamped to ≥ 0 to absorb clock skew. Present only on `cache: hit`. `GET /v1/scrape/{id}` reports `cache: hit` without this field: the age is a property of the replay that happened at completion time, is not persisted on the row, and cannot be derived honestly afterwards. */
1831
1980
  cache_age_s?: number;
1832
1981
  };
1833
1982
  /**
1834
- * @description Terminal asynchronous scrape failures are delivered to subscribers of `failed` as this payload with `X-ByteKit-Event: scrape.failed`.
1983
+ * @description The canonical terminal failure payload. It is returned inline on a `POST /v1/scrape` that fails upstream (HTTP 200, `id: null`), by `GET /v1/scrape/{id}` once a queued job has failed, and delivered to subscribers of `failed` with `X-ByteKit-Event: scrape.failed`.
1835
1984
  * @example {
1836
1985
  * "schema_version": 1,
1837
1986
  * "status": "failed",
@@ -1872,7 +2021,7 @@ export interface components {
1872
2021
  * "status": "queued",
1873
2022
  * "id": "sc_01j9abc123",
1874
2023
  * "url": "https://example.com",
1875
- * "status_url": "https://api.bytekit.com/v1/scrape/sc_01j9abc123",
2024
+ * "status_url": "/v1/scrape/sc_01j9abc123",
1876
2025
  * "queued_at": "2025-01-15T12:00:00Z",
1877
2026
  * "events": []
1878
2027
  * }
@@ -1892,7 +2041,7 @@ export interface components {
1892
2041
  id: string;
1893
2042
  /** Format: uri */
1894
2043
  url: string;
1895
- /** Format: uri */
2044
+ /** @description Root-relative path to poll for this job's terminal envelope — not an absolute URI. Join it onto the base URL of the server you called (see `servers`; they carry no trailing slash) to get the pollable URL, e.g. `https://api.bytekit.com` + `/v1/scrape/sc_01j9abc123`. */
1896
2045
  status_url: string;
1897
2046
  /** Format: date-time */
1898
2047
  queued_at: string;
@@ -2158,7 +2307,7 @@ export interface components {
2158
2307
  options?: {
2159
2308
  [key: string]: unknown;
2160
2309
  };
2161
- /** @description Scrape monitor options (formats, country, headers, etc.). Only for type=scrape. */
2310
+ /** @description Scrape monitor options (formats, country, wait_for_selector, wait_until, delay_ms). Only for type=scrape. */
2162
2311
  scrape_options?: {
2163
2312
  [key: string]: unknown;
2164
2313
  };
@@ -2227,7 +2376,7 @@ export interface components {
2227
2376
  consecutive_failures: number;
2228
2377
  /** @description Error code from the most recent failed capture, if any. */
2229
2378
  last_error_code: string | null;
2230
- /** @description Reason the monitor was auto-suspended (e.g. "auto_suspended_consecutive_failures"), if applicable. */
2379
+ /** @description Reason the monitor was auto-suspended, if applicable. `insufficient_balance` means the account ran out of spendable balance; `auto_suspended_consecutive_failures` means the monitor failed too many times in a row. Either way the monitor stops capturing until it is reactivated by sending `status: "active"` to `PATCH /v1/monitors/{id}`. */
2231
2380
  suspension_reason: string | null;
2232
2381
  metadata: Record<string, never> | null;
2233
2382
  /** Format: date-time */
@@ -2536,7 +2685,7 @@ export interface components {
2536
2685
  /** Format: date-time */
2537
2686
  created_at: string;
2538
2687
  };
2539
- /** @description Minimal account shape returned by GET /v1/account when authenticated with a Clerk session JWT. Omits api_key, subscription, and auto_topup. */
2688
+ /** @description Minimal account shape returned by GET /v1/account when authenticated with a Clerk session JWT. Omits api_key, subscription, and auto_topup; the single boolean `has_subscription` stands in for the bearer path's `subscription` object. */
2540
2689
  AccountSessionResponse: {
2541
2690
  id: string;
2542
2691
  email: string;
@@ -2569,6 +2718,42 @@ export interface components {
2569
2718
  created_at: string;
2570
2719
  /** @description True once the account has SUCCESSFULLY COMPLETED at least one billable request (a scrape/screenshot/fetch/… that settled and was charged credits), regardless of whether it was authenticated with a Clerk session or an API key. All-time — never windowed. A request that failed does not flip it, even when its bandwidth was billed: the monitor terminal-preflight-failure path records bytes without credits, and only the credited settlement counts here. Powers the dashboard onboarding gate — the app shows the guided onboarding flow until this is true, then the dashboard. Lags by up to one usage rollup: the completion service writes the row after the response is returned, so a just-completed first request may still read false for a moment. Treat that as "not visible yet", never as "this account has never made a request". */
2571
2720
  has_activity: boolean;
2721
+ /** @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. */
2722
+ has_subscription: boolean;
2723
+ };
2724
+ /** @description Account shape returned by PATCH /v1/account. Identical to AccountSessionResponse except that it omits `has_activity`: the PATCH handler returns the shared session-account body unchanged and does not run the extra activity lookup that GET /v1/account layers on top of it (issue #4187). */
2725
+ AccountPatchResponse: {
2726
+ id: string;
2727
+ email: string;
2728
+ name: string | null;
2729
+ plan: {
2730
+ id: string;
2731
+ slug: string;
2732
+ name: string;
2733
+ included_screenshots: number;
2734
+ has_overage: boolean;
2735
+ overage_price_cents: number | null;
2736
+ max_concurrency: number;
2737
+ rate_limit_per_sec: number;
2738
+ max_bulk_size: number;
2739
+ max_monitors: number;
2740
+ retention_days: number;
2741
+ };
2742
+ /** @description Prefixed user id of the calling admin user. Null for non-admin members. */
2743
+ owner_user_id: string | null;
2744
+ /** @description Account notification preferences (bandwidth alerts). */
2745
+ notifications: {
2746
+ /** @description Whether the account admin wants an email when bandwidth reaches 80 % of the plan limit. */
2747
+ bandwidth_80_enabled: boolean;
2748
+ /** @description Whether the account admin wants an email when bandwidth reaches 100 % of the plan limit. */
2749
+ bandwidth_100_enabled: boolean;
2750
+ };
2751
+ /** @description The Terms of Service version this account has accepted. An empty string means the account predates clickwrap acceptance (issue #1025). The dashboard diffs this against the published current version to decide whether to show the re-acceptance prompt. */
2752
+ terms_version: string;
2753
+ /** @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. */
2754
+ has_subscription: boolean;
2755
+ /** Format: date-time */
2756
+ created_at: string;
2572
2757
  };
2573
2758
  /** @description Partial update payload for PATCH /v1/account. All fields are optional; at least one of name, email, or notifications must be provided. */
2574
2759
  PatchAccountRequest: {
@@ -2616,7 +2801,7 @@ export interface components {
2616
2801
  purchased_topup_bytes: number;
2617
2802
  /** @description Bytes remaining in starter-grant lots, after active refund reservations. Purchased top-up bytes are excluded. */
2618
2803
  granted_topup_bytes: number;
2619
- /** @description Unspent subscription allowance carried over from earlier billing periods: bytes remaining in allowance lots granted before the current period started, after active refund reservations. Carried value is spent before the current period's allowance, so this falls to `0` before `limit_bytes` reaches the current allowance alone. */
2804
+ /** @description Unspent subscription allowance carried over from earlier billing periods: bytes remaining in allowance lots granted before the current period started, after active refund reservations. While your plan tier is unchanged, earlier lots are drawn first, so carried-over allowance is spent before the current period's; after an upgrade, allowance acquired at the higher tier is drawn first. Value is spent in one order: your plan's included allowance, including any rollover from earlier periods, then purchased top-ups, then the one-time starter grant. */
2620
2805
  rollover_bytes: number;
2621
2806
  };
2622
2807
  CreditBalance: {
@@ -2898,7 +3083,7 @@ export interface operations {
2898
3083
  [name: string]: unknown;
2899
3084
  };
2900
3085
  content: {
2901
- "application/json": components["schemas"]["Account"];
3086
+ "application/json": components["schemas"]["AccountPatchResponse"];
2902
3087
  };
2903
3088
  };
2904
3089
  /** @description Missing or invalid Clerk JWT. */
@@ -3198,7 +3383,7 @@ export interface operations {
3198
3383
  "X-Screenshot-Status"?: string;
3199
3384
  /** @description The originally requested URL. */
3200
3385
  "X-Screenshot-URL"?: string;
3201
- /** @description Credits charged for this screenshot. */
3386
+ /** @description Legacy credit weight for this capture (1, 2 or 4, doubling for `full_page` and again for retina/mobile). It is recorded for reporting only — screenshots are billed on bandwidth, not credits: the charge is the Phase 1 wire bytes x 1.5, and zero when Phase 1 is skipped or fails. */
3202
3387
  "X-Screenshot-Credits-Charged"?: number;
3203
3388
  /** @description Handler elapsed time in milliseconds. */
3204
3389
  "X-Screenshot-Duration-Ms"?: number;
@@ -3239,7 +3424,7 @@ export interface operations {
3239
3424
  "X-Screenshot-Status"?: string;
3240
3425
  /** @description The originally requested URL. */
3241
3426
  "X-Screenshot-URL"?: string;
3242
- /** @description Credits charged for this screenshot. */
3427
+ /** @description Legacy credit weight for this capture (1, 2 or 4, doubling for `full_page` and again for retina/mobile). It is recorded for reporting only — screenshots are billed on bandwidth, not credits: the charge is the Phase 1 wire bytes x 1.5, and zero when Phase 1 is skipped or fails. */
3243
3428
  "X-Screenshot-Credits-Charged"?: number;
3244
3429
  /** @description Handler elapsed time in milliseconds. */
3245
3430
  "X-Screenshot-Duration-Ms"?: number;
@@ -3415,7 +3600,7 @@ export interface operations {
3415
3600
  };
3416
3601
  };
3417
3602
  responses: {
3418
- /** @description Scrape completed synchronously. */
3603
+ /** @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 ends before any job row exists, so its envelope carries `id: null` and there is nothing to poll; `error.http_status` is present only when a real upstream HTTP status is known. */
3419
3604
  200: {
3420
3605
  headers: {
3421
3606
  /** @description Stable scrape identifier (also present on the envelope as `id`). */
@@ -3466,9 +3651,9 @@ export interface operations {
3466
3651
  "X-Scrape-Markdown-URL"?: string;
3467
3652
  /** @description Byte length of the markdown artifact. Present only on fast-path responses when formats includes markdown. */
3468
3653
  "X-Scrape-Markdown-Length"?: number;
3469
- /** @description Numeric proxy tier used (diagnostic). Deprecated — use X-Scrape-Proxy-Tier-Label. */
3654
+ /** @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. */
3470
3655
  "X-Scrape-Proxy-Tier"?: number;
3471
- /** @description Human-readable proxy tier label (e.g. residential, datacenter). Present on fast-path responses. */
3656
+ /** @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. */
3472
3657
  "X-Scrape-Proxy-Tier-Label"?: string;
3473
3658
  /** @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. */
3474
3659
  "X-Scrape-Waf"?: string;
@@ -3479,10 +3664,10 @@ export interface operations {
3479
3664
  [name: string]: unknown;
3480
3665
  };
3481
3666
  content: {
3482
- "application/json": components["schemas"]["ScrapeSuccessEnvelope"];
3667
+ "application/json": components["schemas"]["ScrapeSuccessEnvelope"] | components["schemas"]["ScrapeErrorEnvelope"];
3483
3668
  };
3484
3669
  };
3485
- /** @description Scrape accepted for async processing. */
3670
+ /** @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. */
3486
3671
  202: {
3487
3672
  headers: {
3488
3673
  /** @description Stable scrape identifier for the queued job. */
@@ -3771,7 +3956,14 @@ export interface operations {
3771
3956
  };
3772
3957
  getScrapeBulk: {
3773
3958
  parameters: {
3774
- query?: never;
3959
+ query?: {
3960
+ /** @description Opaque cursor returned by the preceding page. It is bound to this bulk id, this recovery route, and the exact status filter; cross-scope cursors return 422. */
3961
+ cursor?: string;
3962
+ /** @description Maximum result rows considered for this page; the 16-MiB response bound may stop sooner. */
3963
+ limit?: number;
3964
+ /** @description Optional item-status filter. A cursor may be reused only with the same filter. */
3965
+ status?: "pending" | "processing" | "completed" | "failed" | "cancelled";
3966
+ };
3775
3967
  header?: never;
3776
3968
  path: {
3777
3969
  id: string;
@@ -3810,8 +4002,12 @@ export interface operations {
3810
4002
  estimated_credits: number | null;
3811
4003
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
3812
4004
  webhook_url: string;
3813
- /** @description Rehydrated per-URL scrape envelopes — the terminal page of results (default 100 rows, `?limit=` up to 500). `routes/scrape-bulk.ts` spreads this key into the SAME body on both status branches, so it is present here exactly as it is on the 202; on the 200 the entries carry their final success or error envelopes (issue #3632). */
3814
- items: components["schemas"]["ScrapeEnvelope"][];
4005
+ /** @description Opaque cursor for the next stable page; null when traversal is complete. */
4006
+ next_cursor: string | null;
4007
+ /** @description True when another page is available through `next_cursor`. */
4008
+ has_more: boolean;
4009
+ /** @description Rehydrated per-URL scrape envelopes — the terminal page of results (default 500 rows, `?limit=` up to 500). `routes/scrape-bulk.ts` spreads this key into the SAME body on both status branches, so it is present here exactly as it is on the 202; on the 200 the entries carry their final success or error envelopes (issue #3632). */
4010
+ items: (components["schemas"]["ScrapeEnvelope"] | components["schemas"]["BulkMandatoryScrapeItem"])[];
3815
4011
  };
3816
4012
  };
3817
4013
  };
@@ -3845,8 +4041,12 @@ export interface operations {
3845
4041
  estimated_credits: number | null;
3846
4042
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
3847
4043
  webhook_url: string;
3848
- /** @description Rehydrated per-URL scrape envelopes — the same page the 200 returns (default 100 rows, `?limit=` up to 500). While the job is non-terminal most entries carry the `queued` envelope. */
3849
- items: components["schemas"]["ScrapeEnvelope"][];
4044
+ /** @description Opaque cursor for the next stable page; null when traversal is complete. */
4045
+ next_cursor: string | null;
4046
+ /** @description True when another page is available through `next_cursor`. */
4047
+ has_more: boolean;
4048
+ /** @description Rehydrated per-URL scrape envelopes — the same page the 200 returns (default 500 rows, `?limit=` up to 500). While the job is non-terminal most entries carry the `queued` envelope. */
4049
+ items: (components["schemas"]["ScrapeEnvelope"] | components["schemas"]["BulkMandatoryScrapeItem"])[];
3850
4050
  };
3851
4051
  };
3852
4052
  };
@@ -4212,7 +4412,14 @@ export interface operations {
4212
4412
  };
4213
4413
  getFetchBulk: {
4214
4414
  parameters: {
4215
- query?: never;
4415
+ query?: {
4416
+ /** @description Opaque cursor returned by the preceding page. It is bound to this bulk id, this recovery route, and the exact status filter; cross-scope cursors return 422. */
4417
+ cursor?: string;
4418
+ /** @description Maximum result rows considered for this page; the 16-MiB response bound may stop sooner. */
4419
+ limit?: number;
4420
+ /** @description Optional item-status filter. A cursor may be reused only with the same filter. */
4421
+ status?: "pending" | "processing" | "completed" | "failed" | "cancelled";
4422
+ };
4216
4423
  header?: never;
4217
4424
  path: {
4218
4425
  id: string;
@@ -4245,8 +4452,12 @@ export interface operations {
4245
4452
  estimated_credits: number | null;
4246
4453
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
4247
4454
  webhook_url: string;
4248
- /** @description Per-URL fetch items, oldest first, capped at 500 (listBulkFetchItemsWithLatestAttempt). */
4249
- items: {
4455
+ /** @description Opaque cursor for the next stable page; null when traversal is complete. */
4456
+ next_cursor: string | null;
4457
+ /** @description True when another page is available through `next_cursor`. */
4458
+ has_more: boolean;
4459
+ /** @description Stable per-URL fetch items, oldest first. Follow `next_cursor` while `has_more` is true to enumerate the complete filtered job; each page considers at most 500 rows and is bounded to 16 MiB. */
4460
+ items: ({
4250
4461
  /**
4251
4462
  * @description Scrape-row id, `sc_`-prefixed. Fetch-bulk items are rows of the same resource sync `/v1/scrape` returns, so they share its prefix. Not to be confused with the `ft_`-prefixed `X-Fetch-ID` correlation header on sync `/v1/fetch`, which identifies a request rather than a stored item.
4252
4463
  * @example sc_01j9abc123
@@ -4256,25 +4467,46 @@ export interface operations {
4256
4467
  url: string;
4257
4468
  /** @enum {string} */
4258
4469
  status: "pending" | "processing" | "completed" | "failed" | "cancelled";
4259
- content_type: string | null;
4260
- content_length: number | null;
4261
- /** @description Pre-signed download URL for the fetched body, valid for 600 seconds (10 minutes) from the moment this response was generated — matching the signing TTL of `image_url` on `GET /v1/bulk/{id}/screenshots`. A new signature is minted on every poll. Null for items with no stored body; a completed item whose object cannot be signed falls back to the unsigned stored URL, which returns 401 on download. */
4470
+ content_type?: string | null;
4471
+ content_length?: number | null;
4472
+ /** @description Pre-signed download URL for the fetched body, valid for 600 seconds (10 minutes) from the moment this response was generated — matching the signing TTL of `image_url` on `GET /v1/bulk/{id}/screenshots`. A new signature is minted on every poll. Null for items with no stored body or whose object cannot be signed. In the latter case `error_code` is `artifact_unavailable`; the private unsigned storage URL is never returned. */
4262
4473
  content_url: string | null;
4263
- waf_vendor: string | null;
4264
- cache_hit: boolean;
4474
+ waf_vendor?: string | null;
4475
+ cache_hit?: boolean;
4265
4476
  /**
4266
4477
  * @description Itemised account of this item's charge — the basis, the named factors
4267
4478
  * that composed the multiplier, and the resulting billed bytes. Omitted
4268
4479
  * for rows that completed before the billing node was persisted.
4269
4480
  */
4270
4481
  billing?: components["schemas"]["BillingNode"];
4482
+ /** @description Stable item-local error code. `artifact_unavailable` means the stored result or a usable signed reference could not be produced. */
4271
4483
  error_code: string | null;
4272
4484
  error_message: string | null;
4273
4485
  /** Format: date-time */
4274
- created_at: string;
4486
+ created_at?: string;
4275
4487
  /** Format: date-time */
4276
- completed_at: string | null;
4277
- }[];
4488
+ completed_at?: string | null;
4489
+ } | {
4490
+ /**
4491
+ * @description Scrape-row id, `sc_`-prefixed — the same stable identity the ordinary item carries, so recovery pagination is unaffected.
4492
+ * @example sc_01j9abc123
4493
+ */
4494
+ id: string;
4495
+ /** @enum {string} */
4496
+ type: "fetch";
4497
+ /**
4498
+ * @description Terminal state of the item. This is the contract's terminal signal and outranks the ordinary item's legacy `status` spelling.
4499
+ * @enum {string}
4500
+ */
4501
+ terminal_outcome: "pending" | "processing" | "completed" | "failed" | "cancelled";
4502
+ /** Format: uri */
4503
+ url: string;
4504
+ /** @description Bounded pre-signed download URL retained from the ordinary item, or `null` when the reference did not fit or could not be produced. */
4505
+ content_url: string | null;
4506
+ error_code: string | null;
4507
+ /** @description Bounded failure detail; a long message is truncated. */
4508
+ error_message: string | null;
4509
+ })[];
4278
4510
  };
4279
4511
  };
4280
4512
  };
@@ -4311,8 +4543,12 @@ export interface operations {
4311
4543
  estimated_credits: number | null;
4312
4544
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
4313
4545
  webhook_url: string;
4314
- /** @description Per-URL fetch items, oldest first, capped at 500 (listBulkFetchItemsWithLatestAttempt). */
4315
- items: {
4546
+ /** @description Opaque cursor for the next stable page; null when traversal is complete. */
4547
+ next_cursor: string | null;
4548
+ /** @description True when another page is available through `next_cursor`. */
4549
+ has_more: boolean;
4550
+ /** @description Stable per-URL fetch items, oldest first. Follow `next_cursor` while `has_more` is true to enumerate the complete filtered job; each page considers at most 500 rows and is bounded to 16 MiB. */
4551
+ items: ({
4316
4552
  /**
4317
4553
  * @description Scrape-row id, `sc_`-prefixed. Fetch-bulk items are rows of the same resource sync `/v1/scrape` returns, so they share its prefix. Not to be confused with the `ft_`-prefixed `X-Fetch-ID` correlation header on sync `/v1/fetch`, which identifies a request rather than a stored item.
4318
4554
  * @example sc_01j9abc123
@@ -4322,25 +4558,46 @@ export interface operations {
4322
4558
  url: string;
4323
4559
  /** @enum {string} */
4324
4560
  status: "pending" | "processing" | "completed" | "failed" | "cancelled";
4325
- content_type: string | null;
4326
- content_length: number | null;
4327
- /** @description Pre-signed download URL for the fetched body, valid for 600 seconds (10 minutes) from the moment this response was generated — matching the signing TTL of `image_url` on `GET /v1/bulk/{id}/screenshots`. A new signature is minted on every poll. Null for items with no stored body; a completed item whose object cannot be signed falls back to the unsigned stored URL, which returns 401 on download. */
4561
+ content_type?: string | null;
4562
+ content_length?: number | null;
4563
+ /** @description Pre-signed download URL for the fetched body, valid for 600 seconds (10 minutes) from the moment this response was generated — matching the signing TTL of `image_url` on `GET /v1/bulk/{id}/screenshots`. A new signature is minted on every poll. Null for items with no stored body or whose object cannot be signed. In the latter case `error_code` is `artifact_unavailable`; the private unsigned storage URL is never returned. */
4328
4564
  content_url: string | null;
4329
- waf_vendor: string | null;
4330
- cache_hit: boolean;
4565
+ waf_vendor?: string | null;
4566
+ cache_hit?: boolean;
4331
4567
  /**
4332
4568
  * @description Itemised account of this item's charge — the basis, the named factors
4333
4569
  * that composed the multiplier, and the resulting billed bytes. Omitted
4334
4570
  * for rows that completed before the billing node was persisted.
4335
4571
  */
4336
4572
  billing?: components["schemas"]["BillingNode"];
4573
+ /** @description Stable item-local error code. `artifact_unavailable` means the stored result or a usable signed reference could not be produced. */
4337
4574
  error_code: string | null;
4338
4575
  error_message: string | null;
4339
4576
  /** Format: date-time */
4340
- created_at: string;
4577
+ created_at?: string;
4341
4578
  /** Format: date-time */
4342
- completed_at: string | null;
4343
- }[];
4579
+ completed_at?: string | null;
4580
+ } | {
4581
+ /**
4582
+ * @description Scrape-row id, `sc_`-prefixed — the same stable identity the ordinary item carries, so recovery pagination is unaffected.
4583
+ * @example sc_01j9abc123
4584
+ */
4585
+ id: string;
4586
+ /** @enum {string} */
4587
+ type: "fetch";
4588
+ /**
4589
+ * @description Terminal state of the item. This is the contract's terminal signal and outranks the ordinary item's legacy `status` spelling.
4590
+ * @enum {string}
4591
+ */
4592
+ terminal_outcome: "pending" | "processing" | "completed" | "failed" | "cancelled";
4593
+ /** Format: uri */
4594
+ url: string;
4595
+ /** @description Bounded pre-signed download URL retained from the ordinary item, or `null` when the reference did not fit or could not be produced. */
4596
+ content_url: string | null;
4597
+ error_code: string | null;
4598
+ /** @description Bounded failure detail; a long message is truncated. */
4599
+ error_message: string | null;
4600
+ })[];
4344
4601
  };
4345
4602
  };
4346
4603
  };
@@ -4781,7 +5038,14 @@ export interface operations {
4781
5038
  };
4782
5039
  listBulkScreenshots: {
4783
5040
  parameters: {
4784
- query?: never;
5041
+ query?: {
5042
+ /** @description Opaque per-type seek cursor returned by the preceding page. It is bound to this bulk id, this mixed recovery route, and the exact status filter; cross-scope cursors return 422. */
5043
+ cursor?: string;
5044
+ /** @description Maximum rows selected per requested item type; the 16-MiB response bound may stop sooner. */
5045
+ limit?: number;
5046
+ /** @description Optional item-status filter. A cursor may be reused only with the same filter. */
5047
+ status?: "pending" | "processing" | "completed" | "failed" | "cancelled";
5048
+ };
4785
5049
  header?: never;
4786
5050
  path: {
4787
5051
  id: string;
@@ -4801,8 +5065,13 @@ export interface operations {
4801
5065
  bulk_id: string;
4802
5066
  /** @description Number of items in `items` (page size, not the job total). */
4803
5067
  total: number;
5068
+ /** @description Opaque per-type cursor for the next stable page; null when every selected item type is exhausted. Never advances past an item omitted by the byte bound. */
5069
+ next_cursor: string | null;
5070
+ /** @description True when another page is available through `next_cursor`. */
5071
+ has_more: boolean;
5072
+ job_counters: components["schemas"]["BulkJobCounters"];
4804
5073
  /** @description Heterogeneous capture items discriminated by `type`. Fields outside the common set are present only for the matching `type`. */
4805
- items: {
5074
+ items: ({
4806
5075
  /** @enum {string} */
4807
5076
  type: "screenshot" | "recording" | "scrape";
4808
5077
  /** @description Prefixed id — `ss_` / `rec_` / `sc_` per `type`. */
@@ -4811,7 +5080,7 @@ export interface operations {
4811
5080
  status: "pending" | "processing" | "completed" | "failed" | "cancelled";
4812
5081
  /** Format: uri */
4813
5082
  url: string;
4814
- credits_charged: number | null;
5083
+ credits_charged?: number | null;
4815
5084
  /**
4816
5085
  * @description Itemised account of this item's charge — the basis, the named factors
4817
5086
  * that composed the multiplier, and the resulting billed bytes. Omitted
@@ -4819,12 +5088,13 @@ export interface operations {
4819
5088
  */
4820
5089
  billing?: components["schemas"]["BillingNode"];
4821
5090
  error_code: string | null;
5091
+ /** @description Bounded human-readable failure detail. */
4822
5092
  error_message: string | null;
4823
5093
  /** Format: date-time */
4824
- created_at: string;
5094
+ created_at?: string;
4825
5095
  /** Format: date-time */
4826
- completed_at: string | null;
4827
- /** @description `type: screenshot` only. Presigned for completed rows with a storage key; raw image_url otherwise. */
5096
+ completed_at?: string | null;
5097
+ /** @description `type: screenshot` only. Pre-signed download URL for the image, minted fresh for completed rows with a storage key and valid for 600 seconds (10 minutes). For every other row the stored value is returned unchanged — `null` while no image has been stored, and otherwise a private, unsigned storage URL that returns 401 on download. That covers non-completed rows, completed rows with no storage key, and completed rows whose object could not be signed; none of them raise an `artifact_warnings` entry. */
4828
5098
  image_url?: string | null;
4829
5099
  /** @description `type: screenshot` and `type: scrape` only. */
4830
5100
  page_title?: string | null;
@@ -4832,7 +5102,7 @@ export interface operations {
4832
5102
  format?: string;
4833
5103
  /** @description `type: recording` only. */
4834
5104
  video_url?: string | null;
4835
- /** @description `type: scrape` only. Pre-signed download URL for the scraped body, valid for 600 seconds (10 minutes) from the moment this response was generated — matching the signing TTL of `image_url` above and of `content_url` on `GET /v1/fetch/bulk/{id}`. A new signature is minted on every poll. Null for items with no stored body; a completed item whose object cannot be signed falls back to the unsigned stored URL, which returns 401 on download. */
5105
+ /** @description `type: scrape` only. Pre-signed download URL for the scraped body, valid for 600 seconds (10 minutes) from the moment this response was generated — matching the signing TTL of `image_url` above and of `content_url` on `GET /v1/fetch/bulk/{id}`. A new signature is minted on every poll for a completed item with a storage key. For every other item the stored value is returned unchanged — `null` while no body 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. */
4836
5106
  content_url?: string | null;
4837
5107
  /** @description `type: scrape` only. */
4838
5108
  content_type?: string | null;
@@ -4840,9 +5110,33 @@ export interface operations {
4840
5110
  content_length?: number | null;
4841
5111
  /** @description `type: scrape` only. Always null in bulk listings — fetch the body via `markdown_url`. */
4842
5112
  markdown?: string | null;
4843
- /** @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. Null for items with no stored markdown; a completed item whose object cannot be signed falls back to the unsigned stored URL, which returns 401 on download. */
5113
+ /** @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. */
4844
5114
  markdown_url?: string | null;
4845
- }[];
5115
+ /** @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`. */
5116
+ artifacts?: {
5117
+ raw: string | null;
5118
+ markdown: string | null;
5119
+ links: null | (string | components["schemas"]["ScrapeScoredLink"])[];
5120
+ images: null | (string | components["schemas"]["ScrapeScoredImage"])[];
5121
+ };
5122
+ /** @description Nonfatal artifact reference failures for this scrape item. */
5123
+ artifact_warnings?: components["schemas"]["ScrapeWarning"][];
5124
+ } | {
5125
+ /** @description Prefixed id — `ss_` / `rec_` / `sc_` per `type`. The same stable identity the ordinary item carries. */
5126
+ id: string;
5127
+ /** @enum {string} */
5128
+ type: "screenshot" | "recording" | "scrape";
5129
+ /**
5130
+ * @description Terminal state of the item. This is the contract's terminal signal and outranks the ordinary item's legacy `status` spelling.
5131
+ * @enum {string}
5132
+ */
5133
+ terminal_outcome: "pending" | "processing" | "completed" | "failed" | "cancelled";
5134
+ /** Format: uri */
5135
+ url: string;
5136
+ error_code: string | null;
5137
+ /** @description Bounded failure detail; a long message is truncated. */
5138
+ error_message: string | null;
5139
+ })[];
4846
5140
  };
4847
5141
  };
4848
5142
  };
@@ -5611,7 +5905,7 @@ export interface operations {
5611
5905
  plan_type: "payg" | "subscription";
5612
5906
  /** @description Total top-up spend in cents for this billing period. Present only in dual/bytes billing mode. */
5613
5907
  topup_spent_cents?: number;
5614
- /** @description Remaining purchased top-up bytes, already net of any overage consumed against them. Equal to topup_bytes. Present only in dual/bytes billing mode. */
5908
+ /** @description Remaining top-up bytes across purchased top-up lots and the one-time starter grant, already net of any overage consumed against them. Equal to topup_bytes. Present only in dual/bytes billing mode. */
5615
5909
  topup_balance_bytes?: number;
5616
5910
  /** @description Days elapsed since period_start. */
5617
5911
  period_days_elapsed: number;
@@ -5621,11 +5915,11 @@ export interface operations {
5621
5915
  bytes_bulk: number;
5622
5916
  bytes_scrape: number;
5623
5917
  bytes_monitor: number;
5624
- /** @description The spendable byte budget for this period, summed over the account's value lots: the allowance granted for the current period, plus unspent allowance carried over from earlier periods, plus purchased top-up and starter-grant bytes. Carried-over value is spent first, so this figure falls as it is consumed. */
5918
+ /** @description The spendable byte budget for this period, summed over the account's value lots: the allowance granted for the current period, plus unspent allowance carried over from earlier periods, plus purchased top-up and starter-grant bytes. The figure falls as those lots are consumed. */
5625
5919
  bytes_limit: number;
5626
5920
  /** @description Bytes still available across every active lot, after active refund reservations. */
5627
5921
  bytes_remaining: number;
5628
- /** @description Unspent allowance carried over from earlier billing periods. */
5922
+ /** @description Unspent allowance carried over from earlier billing periods. Value is spent in one order: your plan's included allowance, including any rollover from earlier periods, then purchased top-ups, then the one-time starter grant. */
5629
5923
  rollover_bytes: number;
5630
5924
  /** @description Bytes remaining in purchased top-up and starter-grant lots. Subscription allowance is excluded. */
5631
5925
  topup_bytes: number;
@@ -5817,7 +6111,7 @@ export interface operations {
5817
6111
  error_message?: string | null;
5818
6112
  /** @description Prefixed key id (ak_) that issued the request. */
5819
6113
  api_key_id?: string | null;
5820
- /** @description Stored content, image or video URL — null when the row has no stored object. For a `completed` row with a stored object this is a **pre-signed** download URL, minted fresh on every read of this endpoint and valid for **600 seconds (10 minutes)** — the same signing lifetime as `content_url` on `GET /v1/fetch/bulk/{id}` and `image_url` on `GET /v1/bulk/{id}/screenshots`. The underlying objects are private, so an unsigned URL returns 401: download inside that window, or re-poll this endpoint for a fresh signature. Rows that are not `completed`, and completed rows whose object cannot be signed, fall back to the unsigned stored URL, which returns 401 on download. */
6114
+ /** @description Stored content, image or video URL. For a `completed` row with a non-empty storage key this is a **pre-signed** download URL, minted fresh on every read of this endpoint and valid for **600 seconds (10 minutes)** — the same signing lifetime as `content_url` on `GET /v1/fetch/bulk/{id}` and `image_url` on `GET /v1/bulk/{id}/screenshots`. Download inside that window, or re-poll this endpoint for a fresh signature. For every other row the stored value is returned unchanged — `null` while no object has been stored, and otherwise a private, unsigned storage URL that returns 401 on download. That covers rows that are not `completed`, completed rows with no storage key, and completed rows whose object could not be signed; this endpoint raises no `artifact_unavailable` signal for any of them. */
5821
6115
  artifact_url?: string | null;
5822
6116
  /** @description The original request options. */
5823
6117
  options?: {
@@ -5978,10 +6272,10 @@ export interface operations {
5978
6272
  content: {
5979
6273
  "application/json": {
5980
6274
  /**
5981
- * @description Bytes to purchase. Allowed tiers — 5, 25, 50, 75, 100 GB.
6275
+ * @description Bytes to purchase. Allowed tiers — 5, 25, 50, 75, 100 GB (1 GB = 1,000,000,000 bytes).
5982
6276
  * @enum {integer}
5983
6277
  */
5984
- bytes: 5368709120 | 26843545600 | 53687091200 | 80530636800 | 107374182400;
6278
+ bytes: 5000000000 | 25000000000 | 50000000000 | 75000000000 | 100000000000;
5985
6279
  /**
5986
6280
  * Format: uri
5987
6281
  * @description Redirect target after a completed Checkout.
@@ -6135,6 +6429,52 @@ export interface operations {
6135
6429
  };
6136
6430
  };
6137
6431
  };
6432
+ getPlanChange: {
6433
+ parameters: {
6434
+ query?: never;
6435
+ header?: never;
6436
+ path?: never;
6437
+ cookie?: never;
6438
+ };
6439
+ requestBody?: never;
6440
+ responses: {
6441
+ /** @description Successful response. */
6442
+ 200: {
6443
+ headers: {
6444
+ [name: string]: unknown;
6445
+ };
6446
+ content: {
6447
+ "application/json": {
6448
+ /** @description The plan the subscription switches to, or null. */
6449
+ pending_plan_slug: string | null;
6450
+ /**
6451
+ * Format: date-time
6452
+ * @description When the booked change lands, or null.
6453
+ */
6454
+ pending_effective_at: string | null;
6455
+ };
6456
+ };
6457
+ };
6458
+ /** @description No subscription. */
6459
+ 400: {
6460
+ headers: {
6461
+ [name: string]: unknown;
6462
+ };
6463
+ content: {
6464
+ "application/json": components["schemas"]["Error"];
6465
+ };
6466
+ };
6467
+ /** @description The Stripe subscription schedule could not be read. */
6468
+ 502: {
6469
+ headers: {
6470
+ [name: string]: unknown;
6471
+ };
6472
+ content: {
6473
+ "application/json": components["schemas"]["Error"];
6474
+ };
6475
+ };
6476
+ };
6477
+ };
6138
6478
  changePlan: {
6139
6479
  parameters: {
6140
6480
  query?: never;
@@ -6151,13 +6491,28 @@ export interface operations {
6151
6491
  };
6152
6492
  };
6153
6493
  responses: {
6154
- /** @description Successful response. */
6494
+ /** @description Upgrades apply immediately (`changed: true`). Downgrades are booked for the end of the paid period (`changed: false`, `pending: true`) so the customer keeps the allowance they already paid for and nothing is prorated. */
6155
6495
  200: {
6156
6496
  headers: {
6157
6497
  [name: string]: unknown;
6158
6498
  };
6159
6499
  content: {
6160
- "application/json": Record<string, never>;
6500
+ "application/json": {
6501
+ /** @description Whether the subscription was re-priced now. */
6502
+ changed: boolean;
6503
+ /** @description Present and true when the change is booked for a later date. */
6504
+ pending?: boolean;
6505
+ previous_plan: string;
6506
+ new_plan: string;
6507
+ subscription_id: string;
6508
+ /**
6509
+ * Format: date-time
6510
+ * @description When a booked change lands. Absent on an immediate change.
6511
+ */
6512
+ effective_at?: string;
6513
+ /** @description Stripe proration behaviour applied. Absent on a booked change. */
6514
+ proration?: string;
6515
+ };
6161
6516
  };
6162
6517
  };
6163
6518
  /** @description No subscription, same plan, or invalid plan. */
@@ -6171,6 +6526,40 @@ export interface operations {
6171
6526
  };
6172
6527
  };
6173
6528
  };
6529
+ revokePlanChange: {
6530
+ parameters: {
6531
+ query?: never;
6532
+ header?: never;
6533
+ path?: never;
6534
+ cookie?: never;
6535
+ };
6536
+ requestBody?: never;
6537
+ responses: {
6538
+ /** @description Successful response. */
6539
+ 200: {
6540
+ headers: {
6541
+ [name: string]: unknown;
6542
+ };
6543
+ content: {
6544
+ "application/json": {
6545
+ revoked: boolean;
6546
+ /** @description The plan the subscription stays on. */
6547
+ plan: string;
6548
+ subscription_id: string;
6549
+ };
6550
+ };
6551
+ };
6552
+ /** @description No subscription, or no scheduled plan change to revoke. */
6553
+ 400: {
6554
+ headers: {
6555
+ [name: string]: unknown;
6556
+ };
6557
+ content: {
6558
+ "application/json": components["schemas"]["Error"];
6559
+ };
6560
+ };
6561
+ };
6562
+ };
6174
6563
  listInvoices: {
6175
6564
  parameters: {
6176
6565
  query?: {
@@ -6234,7 +6623,10 @@ export interface operations {
6234
6623
  };
6235
6624
  content: {
6236
6625
  "application/json": {
6237
- bandwidth: components["schemas"]["BandwidthBalance"];
6626
+ bandwidth: components["schemas"]["BandwidthBalance"] & {
6627
+ /** @description Remaining balance of your subscription allowance: bytes still unspent across all allowance lots, the current period's and any rolled over from earlier periods alike, after active refund reservations. This is a remaining balance and falls to zero as the allowance is drawn down. It is not `included_bytes`, which is the plan's configured grant for a period and does not move as it is spent; do not subtract one from the other. `rollover_bytes` is a subset of this figure. */
6628
+ remaining_allowance_bytes: number;
6629
+ };
6238
6630
  credits: components["schemas"]["CreditBalance"];
6239
6631
  rates: {
6240
6632
  /** @description Bandwidth top-up price in cents per MB. When the authenticated account is on a plan that does not explicitly configure a top-up price (e.g. free, payg, or a custom plan without an explicit value), the API falls back to the rack rate — the highest `topup_price_per_mb_cents` configured across all plans — so the UI never advertises `$0.00/GB`. */
@@ -6272,15 +6664,15 @@ export interface operations {
6272
6664
  content: {
6273
6665
  "application/json": {
6274
6666
  enabled: boolean;
6275
- /** @description Min 1 MB. Required when enabled. */
6667
+ /** @description Min 1 MB (1,000,000 bytes). Required when enabled. */
6276
6668
  threshold_bytes?: number;
6277
6669
  /**
6278
- * @description Allowed tiers — 5, 25, 50, 75, 100 GB. Required when enabled.
6670
+ * @description Allowed tiers — 5, 25, 50, 75, 100 GB (1 GB = 1,000,000,000 bytes). Required when enabled.
6279
6671
  * @enum {integer}
6280
6672
  */
6281
- amount_bytes?: 5368709120 | 26843545600 | 53687091200 | 80530636800 | 107374182400;
6282
- /** @description $1-$1000. Required when enabled. */
6283
- monthly_cap_cents?: number;
6673
+ amount_bytes?: 5000000000 | 25000000000 | 50000000000 | 75000000000 | 100000000000;
6674
+ /** @description $1-$1000, or null for no monthly cap. Required when enabled — send an explicit null to remove the cap; omitting the key is rejected. */
6675
+ monthly_cap_cents?: number | null;
6284
6676
  };
6285
6677
  };
6286
6678
  };