@hunt-labs/bytekit-sdk 0.4.0 → 0.6.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.
@@ -155,6 +155,9 @@ export interface paths {
155
155
  * Capture a screenshot
156
156
  * @description Sync by default (holds up to 28s). Pass `?async=true` to return 202 immediately.
157
157
  * Poll via GET /v1/screenshots/{id}.
158
+ *
159
+ * **Limits:** request bodies are capped at 512 KB. An oversized body
160
+ * returns a `400` with error code `request_too_large`.
158
161
  */
159
162
  post: operations["createScreenshot"];
160
163
  delete?: never;
@@ -277,6 +280,9 @@ export interface paths {
277
280
  /**
278
281
  * Fetch a URL (POST)
279
282
  * @description Same as GET /v1/fetch but with a JSON request body.
283
+ *
284
+ * **Limits:** request bodies are capped at 512 KB. An oversized body
285
+ * returns a `400` with error code `request_too_large`.
280
286
  */
281
287
  post: operations["postFetch"];
282
288
  delete?: never;
@@ -298,6 +304,17 @@ export interface paths {
298
304
  * Bulk fetch URLs
299
305
  * @description Enqueues multiple URLs for HTTP fetching. Results delivered via webhook.
300
306
  * Does not support options that require page rendering (cookies, wait_for_selector, etc.).
307
+ *
308
+ * **Limits:** request bodies are guarded in a two-tier shape. A streamed body
309
+ * with no `Content-Length` header is capped at 2 MB before your API key
310
+ * is checked; a body that declares `Content-Length` is instead bounded
311
+ * there by a 20 MB fail-safe (not the real limit — see below), since
312
+ * that branch reads nothing until your key is verified. Once your key
313
+ * is verified, a second check re-gates the body against your account's
314
+ * own `max_bulk_size` (at this endpoint's per-item override budget),
315
+ * which reaches 16.8 MB for the largest documented account. A
316
+ * standard-plan account's effective ceiling is 2 MB; either tier's
317
+ * overrun returns a `400` with error code `request_too_large`.
301
318
  */
302
319
  post: operations["createFetchBulk"];
303
320
  delete?: never;
@@ -313,7 +330,19 @@ export interface paths {
313
330
  path?: never;
314
331
  cookie?: never;
315
332
  };
316
- /** Get fetch bulk job status */
333
+ /**
334
+ * Get fetch bulk job status
335
+ * @description Returns the job envelope plus its per-URL items.
336
+ *
337
+ * **Downloading item content.** Each completed item's `content_url` is a
338
+ * **pre-signed** URL, minted fresh on every read of this endpoint and valid
339
+ * for **600 seconds (10 minutes)** — the same signing lifetime as the
340
+ * `image_url` returned by `GET /v1/bulk/{id}/screenshots`. The underlying
341
+ * objects are private, so an unsigned URL returns `401`: download the
342
+ * content inside that window, or re-poll this endpoint for a fresh
343
+ * signature. Items that are not `completed`, and completed items with no
344
+ * stored object, carry `null` or the unsigned stored URL instead.
345
+ */
317
346
  get: operations["getFetchBulk"];
318
347
  put?: never;
319
348
  post?: never;
@@ -343,6 +372,17 @@ export interface paths {
343
372
  * Provide `urls` (simple list) or `items` (per-item config), not both.
344
373
  * Webhook deliveries include `X-ByteKit-Event: bulk.completed` so
345
374
  * receivers can dispatch on the header without parsing the body shape.
375
+ *
376
+ * **Limits:** request bodies are guarded in a two-tier shape. A streamed body
377
+ * with no `Content-Length` header is capped at 4 MB before your API key
378
+ * is checked; a body that declares `Content-Length` is instead bounded
379
+ * there by a 32 MB fail-safe (not the real limit — see below), since
380
+ * that branch reads nothing until your key is verified. Once your key
381
+ * is verified, a second check re-gates the body against your account's
382
+ * own `max_bulk_size` (at this endpoint's richer per-item override
383
+ * budget), which reaches 28.7 MB for the largest documented account. A
384
+ * standard-plan account's effective ceiling is 4 MB; either tier's
385
+ * overrun returns a `400` with error code `request_too_large`.
346
386
  */
347
387
  post: operations["createBulk"];
348
388
  delete?: never;
@@ -379,7 +419,20 @@ export interface paths {
379
419
  path?: never;
380
420
  cookie?: never;
381
421
  };
382
- /** List bulk job items */
422
+ /**
423
+ * List bulk job items
424
+ * @description Returns the bulk job's items, discriminated by `type`.
425
+ *
426
+ * **Downloading item artifacts.** `image_url` (`type: screenshot`) and both
427
+ * `content_url` and `markdown_url` (`type: scrape`) are **pre-signed** URLs,
428
+ * minted fresh on every read of this endpoint and valid for **600 seconds
429
+ * (10 minutes)** —
430
+ * the same signing lifetime as `content_url` on `GET /v1/fetch/bulk/{id}`.
431
+ * The underlying objects are private, so an unsigned URL returns `401`:
432
+ * download inside that window, or re-poll this endpoint for a fresh
433
+ * signature. Items that are not `completed`, and completed items with no
434
+ * stored object, carry `null` or the unsigned stored URL instead.
435
+ */
383
436
  get: operations["listBulkScreenshots"];
384
437
  put?: never;
385
438
  post?: never;
@@ -402,6 +455,9 @@ export interface paths {
402
455
  /**
403
456
  * Create a change-detection monitor
404
457
  * @description Creates a recurring change-detection monitor for a URL, delivering results via webhook.
458
+ *
459
+ * **Limits:** request bodies are capped at 512 KB. An oversized body
460
+ * returns a `400` with error code `request_too_large`.
405
461
  */
406
462
  post: operations["createMonitor"];
407
463
  delete?: never;
@@ -462,6 +518,9 @@ export interface paths {
462
518
  * Webhook deliveries include `X-ByteKit-Event: sitemap.completed` or
463
519
  * `X-ByteKit-Event: sitemap.failed` so receivers can dispatch on the
464
520
  * header without parsing the body shape.
521
+ *
522
+ * **Limits:** request bodies are capped at 512 KB. An oversized body
523
+ * returns a `400` with error code `request_too_large`.
465
524
  */
466
525
  post: operations["createSitemap"];
467
526
  delete?: never;
@@ -738,9 +797,9 @@ export interface paths {
738
797
  get?: never;
739
798
  put?: never;
740
799
  /**
741
- * Cancel subscription
742
- * @description Immediately cancels the Stripe subscription with proration.
743
- * Takes a balance snapshot for 6-month grace-period restoration on re-subscribe.
800
+ * Legacy cancellation compatibility terminal
801
+ * @description Returns 410. Customer cancellation is initiated through the hosted
802
+ * Billing Portal and projected through Stripe webhooks.
744
803
  */
745
804
  post: operations["cancelSubscription"];
746
805
  delete?: never;
@@ -917,6 +976,12 @@ export interface paths {
917
976
  /**
918
977
  * Stripe webhook receiver
919
978
  * @description Receives Stripe webhook events. Verified via signature.
979
+ *
980
+ * **Limits:** request bodies are capped at 256 KB — real Stripe event
981
+ * payloads stay in the tens of KB. An oversized body returns a `400`
982
+ * with a bespoke `{ error }` body (this route predates issue #699's
983
+ * unified REST envelope and answers Stripe's own webhook contract, not
984
+ * the public API's error shape).
920
985
  */
921
986
  post: operations["stripeWebhook"];
922
987
  delete?: never;
@@ -954,6 +1019,10 @@ export interface paths {
954
1019
  /**
955
1020
  * Retry a webhook delivery
956
1021
  * @description Requeues a failed or exhausted webhook delivery for another attempt.
1022
+ *
1023
+ * **Limits:** this endpoint takes no request body; any body sent is
1024
+ * capped at 64 KB. An oversized body returns a `400` with error code
1025
+ * `request_too_large`.
957
1026
  */
958
1027
  post: operations["retryWebhookDelivery"];
959
1028
  delete?: never;
@@ -1236,6 +1305,12 @@ export interface paths {
1236
1305
  * Clerk webhook receiver
1237
1306
  * @description Receives Clerk events (user.created, user.updated, user.deleted, etc.).
1238
1307
  * Authentication is via Svix signature verification — no bearer token required.
1308
+ *
1309
+ * **Limits:** request bodies are capped at 256 KB — real Clerk event
1310
+ * payloads (user/membership/invitation objects) stay well under this.
1311
+ * An oversized body returns a `400` with error code `request_too_large`
1312
+ * (bespoke `{ error }` slug shape, matching this route's existing
1313
+ * error convention, not the unified REST envelope).
1239
1314
  */
1240
1315
  post: operations["clerkWebhook"];
1241
1316
  delete?: never;
@@ -2605,6 +2680,15 @@ export interface operations {
2605
2680
  "application/json": components["schemas"]["AccountBearerResponse"] | components["schemas"]["AccountSessionResponse"];
2606
2681
  };
2607
2682
  };
2683
+ /** @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. */
2684
+ 429: {
2685
+ headers: {
2686
+ [name: string]: unknown;
2687
+ };
2688
+ content: {
2689
+ "application/json": components["schemas"]["Error"];
2690
+ };
2691
+ };
2608
2692
  };
2609
2693
  };
2610
2694
  deleteAccount: {
@@ -2690,6 +2774,15 @@ export interface operations {
2690
2774
  "application/json": components["schemas"]["Error"];
2691
2775
  };
2692
2776
  };
2777
+ /** @description Rate limit exceeded (`rate_limited`) — the Clerk-session 60-request/60-second per-user window. Carries a `Retry-After` header derived from the same clock as the window reset. */
2778
+ 429: {
2779
+ headers: {
2780
+ [name: string]: unknown;
2781
+ };
2782
+ content: {
2783
+ "application/json": components["schemas"]["Error"];
2784
+ };
2785
+ };
2693
2786
  };
2694
2787
  };
2695
2788
  listApiKeys: {
@@ -2916,7 +3009,7 @@ export interface operations {
2916
3009
  "application/json": components["schemas"]["Error"];
2917
3010
  };
2918
3011
  };
2919
- /** @description Rate limit exceeded. */
3012
+ /** @description Reveal rate limit exceeded (per-account anti-harvest cap, distinct from the per-second API rate limit). Carries a `Retry-After` header. */
2920
3013
  429: {
2921
3014
  headers: {
2922
3015
  [name: string]: unknown;
@@ -3045,8 +3138,45 @@ export interface operations {
3045
3138
  "application/json": components["schemas"]["Error"];
3046
3139
  };
3047
3140
  };
3048
- /** @description Validation error or screenshot failed. */
3141
+ /**
3142
+ * @description Validation error, or a screenshot that failed inside the sync hold.
3143
+ * The two carry DIFFERENT bodies (issue #2679):
3144
+ *
3145
+ * - A request-validation failure returns the unified `Error` envelope
3146
+ * with code `validation_error`.
3147
+ * - A capture that reached a terminal `failed` state inside the sync
3148
+ * hold returns the full `ScreenshotResponse` resource, whose
3149
+ * `error_code`/`error_message` carry the real failure (`blocked`,
3150
+ * `timeout`, …). This is the canonical shape for that case: the
3151
+ * resource body is what carries the `ss_` handle, `poll_url` and
3152
+ * `expires_at` a client needs to redeem the failed capture, none of
3153
+ * which fit the `Error` envelope.
3154
+ *
3155
+ * Discriminate on the shape of the top-level `error` key. The envelope
3156
+ * form carries `error` as an OBJECT (`{ code, message, http_status,
3157
+ * failed_at }`); the resource form has no `error` key at all, and
3158
+ * carries the flat `error_code`/`error_message` pair plus `id` instead.
3159
+ *
3160
+ * Do NOT discriminate on `status`. Both forms carry
3161
+ * `"status": "failed"` on this response — `Error.status` is a required
3162
+ * property with `enum: [failed]` — so it separates nothing here.
3163
+ *
3164
+ * `X-Screenshot-ID` accompanies the resource form only: a
3165
+ * request-validation failure is raised before a screenshot row exists,
3166
+ * so no screenshot headers travel with it.
3167
+ */
3049
3168
  422: {
3169
+ headers: {
3170
+ /** @description Stable screenshot identifier (matches `id` in the resource body). Emitted only on the failed-capture variant; absent on a request-validation failure. */
3171
+ "X-Screenshot-ID"?: string;
3172
+ [name: string]: unknown;
3173
+ };
3174
+ content: {
3175
+ "application/json": components["schemas"]["Error"] | components["schemas"]["ScreenshotResponse"];
3176
+ };
3177
+ };
3178
+ /** @description Rate limit (`rate_limited`) or concurrency limit (`concurrency_limit`) exceeded. Carries a `Retry-After` header — seconds derived from the same clock as `X-RateLimit-Reset` for the rate-limit variant, a fixed small back-off for the concurrency variant. */
3179
+ 429: {
3050
3180
  headers: {
3051
3181
  [name: string]: unknown;
3052
3182
  };
@@ -3246,7 +3376,7 @@ export interface operations {
3246
3376
  "application/json": components["schemas"]["Error"];
3247
3377
  };
3248
3378
  };
3249
- /** @description Rate limit exceeded. */
3379
+ /** @description Rate limit (`rate_limited`) or concurrency limit (`concurrency_limit`) exceeded. Carries a `Retry-After` header — seconds derived from the same clock as `X-RateLimit-Reset` for the rate-limit variant, a fixed small back-off for the concurrency variant. */
3250
3380
  429: {
3251
3381
  headers: {
3252
3382
  [name: string]: unknown;
@@ -3446,8 +3576,9 @@ export interface operations {
3446
3576
  created_at: string;
3447
3577
  /** Format: date-time */
3448
3578
  completed_at: string | null;
3449
- total_credits_charged: number;
3450
- /** @description Estimated credits at submission time. Null in GET responses. */
3579
+ /** @description Always null on the create response — the job has not been billed yet (routes/scrape-bulk.ts builds the 202 body from a partial job row). Fractional when populated (credits are NUMERIC(10,2)); the numeric branch is unreachable on this path and exists only so the 202 and 200 bodies share one shape. */
3580
+ total_credits_charged: number | null;
3581
+ /** @description Estimated credits at submission time. Null in GET responses. Fractional — markdown/html formats weigh 0.5 credits each (scrape-shared/src/credits.ts), so a one-item markdown job is 1.5. */
3451
3582
  estimated_credits: number | null;
3452
3583
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
3453
3584
  webhook_url: string;
@@ -3523,7 +3654,8 @@ export interface operations {
3523
3654
  created_at: string;
3524
3655
  /** Format: date-time */
3525
3656
  completed_at: string | null;
3526
- total_credits_charged: number;
3657
+ /** @description Total credits billed for the job. Null until the job is billed. Fractional — credits are NUMERIC(10,2). */
3658
+ total_credits_charged: number | null;
3527
3659
  /** @description Null in GET responses (computed at submission time only). */
3528
3660
  estimated_credits: number | null;
3529
3661
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
@@ -3610,6 +3742,15 @@ export interface operations {
3610
3742
  "application/json": components["schemas"]["Error"];
3611
3743
  };
3612
3744
  };
3745
+ /** @description Rate limit (`rate_limited`) or concurrency limit (`concurrency_limit`) exceeded. Carries a `Retry-After` header — seconds derived from the same clock as `X-RateLimit-Reset` for the rate-limit variant, a fixed small back-off for the concurrency variant. */
3746
+ 429: {
3747
+ headers: {
3748
+ [name: string]: unknown;
3749
+ };
3750
+ content: {
3751
+ "application/json": components["schemas"]["Error"];
3752
+ };
3753
+ };
3613
3754
  /**
3614
3755
  * @description Fetch service unavailable, content transform failed, or a non-2xx upstream
3615
3756
  * response relayed as the unified Error envelope. On an upstream relay the HTTP
@@ -3699,6 +3840,15 @@ export interface operations {
3699
3840
  "application/json": components["schemas"]["Error"];
3700
3841
  };
3701
3842
  };
3843
+ /** @description Rate limit (`rate_limited`) or concurrency limit (`concurrency_limit`) exceeded. Carries a `Retry-After` header — seconds derived from the same clock as `X-RateLimit-Reset` for the rate-limit variant, a fixed small back-off for the concurrency variant. */
3844
+ 429: {
3845
+ headers: {
3846
+ [name: string]: unknown;
3847
+ };
3848
+ content: {
3849
+ "application/json": components["schemas"]["Error"];
3850
+ };
3851
+ };
3702
3852
  /**
3703
3853
  * @description Fetch service unavailable, content transform failed, or a non-2xx upstream
3704
3854
  * response relayed as the unified Error envelope. On an upstream relay the HTTP
@@ -3758,7 +3908,25 @@ export interface operations {
3758
3908
  [name: string]: unknown;
3759
3909
  };
3760
3910
  content: {
3761
- "application/json": Record<string, never>;
3911
+ "application/json": {
3912
+ /** @example bulk_01j9abc123 */
3913
+ id: string;
3914
+ /** @enum {string} */
3915
+ status: "processing" | "completed" | "failed";
3916
+ total: number;
3917
+ completed: number;
3918
+ failed: number;
3919
+ /** Format: date-time */
3920
+ created_at: string;
3921
+ /** Format: date-time */
3922
+ completed_at: string | null;
3923
+ /** @description Always null on the create response — the job has not been billed yet (routes/fetch-bulk.ts builds the 202 body from a partial job row). Fractional when populated (credits are NUMERIC(10,2)); the numeric branch is unreachable on this path and exists only so the 202 and 200 bodies share one shape. */
3924
+ total_credits_charged: number | null;
3925
+ /** @description Estimated credits at submission time. Null in GET responses. Fractional — markdown/html formats weigh 0.5 credits each (scrape-shared/src/credits.ts), so a one-item markdown job is 1.5. */
3926
+ estimated_credits: number | null;
3927
+ /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
3928
+ webhook_url: string;
3929
+ };
3762
3930
  };
3763
3931
  };
3764
3932
  /**
@@ -3812,7 +3980,49 @@ export interface operations {
3812
3980
  [name: string]: unknown;
3813
3981
  };
3814
3982
  content: {
3815
- "application/json": Record<string, never>;
3983
+ "application/json": {
3984
+ /** @example bulk_01j9abc123 */
3985
+ id: string;
3986
+ /** @enum {string} */
3987
+ status: "processing" | "completed" | "failed";
3988
+ total: number;
3989
+ completed: number;
3990
+ failed: number;
3991
+ /** Format: date-time */
3992
+ created_at: string;
3993
+ /** Format: date-time */
3994
+ completed_at: string | null;
3995
+ /** @description Total credits billed for the job. Null until the job is billed. Fractional — credits are NUMERIC(10,2). */
3996
+ total_credits_charged: number | null;
3997
+ /** @description Null in GET responses (computed at submission time only). */
3998
+ estimated_credits: number | null;
3999
+ /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
4000
+ webhook_url: string;
4001
+ /** @description Per-URL fetch items, oldest first, capped at 500 (listBulkFetchItemsWithLatestAttempt). */
4002
+ items: {
4003
+ /**
4004
+ * @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.
4005
+ * @example sc_01j9abc123
4006
+ */
4007
+ id: string;
4008
+ /** Format: uri */
4009
+ url: string;
4010
+ /** @enum {string} */
4011
+ status: "pending" | "processing" | "completed" | "failed" | "cancelled";
4012
+ content_type: string | null;
4013
+ content_length: number | null;
4014
+ /** @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. */
4015
+ content_url: string | null;
4016
+ waf_vendor: string | null;
4017
+ cache_hit: boolean;
4018
+ error_code: string | null;
4019
+ error_message: string | null;
4020
+ /** Format: date-time */
4021
+ created_at: string;
4022
+ /** Format: date-time */
4023
+ completed_at: string | null;
4024
+ }[];
4025
+ };
3816
4026
  };
3817
4027
  };
3818
4028
  /** @description Resource not found. */
@@ -3855,7 +4065,8 @@ export interface operations {
3855
4065
  created_at: string;
3856
4066
  /** Format: date-time */
3857
4067
  completed_at: string | null;
3858
- total_credits_charged: number;
4068
+ /** @description Total credits billed for the job. Null until the job is billed. Fractional — credits are NUMERIC(10,2). */
4069
+ total_credits_charged: number | null;
3859
4070
  /** @description Null in GET responses (computed at submission time only). */
3860
4071
  estimated_credits: number | null;
3861
4072
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
@@ -3938,7 +4149,7 @@ export interface operations {
3938
4149
  /** Format: uri */
3939
4150
  url: string;
3940
4151
  /**
3941
- * @default screenshot
4152
+ * @description Capture kind for this entry. If omitted, inherits `defaults.type`; if that is also omitted, falls back to `screenshot`.
3942
4153
  * @enum {string}
3943
4154
  */
3944
4155
  type?: "screenshot" | "scrape";
@@ -4060,8 +4271,9 @@ export interface operations {
4060
4271
  created_at: string;
4061
4272
  /** Format: date-time */
4062
4273
  completed_at: string | null;
4063
- total_credits_charged: number;
4064
- /** @description Estimated credits at submission time. Null in GET responses. */
4274
+ /** @description Always null on the create response — the job has not been billed yet (routes/bulk.ts builds the 202 body from a partial job row). Fractional when populated (credits are NUMERIC(10,2)); the numeric branch is unreachable on this path and exists only so the 202 and 200 bodies share one shape. */
4275
+ total_credits_charged: number | null;
4276
+ /** @description Estimated credits at submission time. Null in GET responses. Fractional — markdown/html formats weigh 0.5 credits each (scrape-shared/src/credits.ts), so a one-item markdown job is 1.5. */
4065
4277
  estimated_credits: number | null;
4066
4278
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
4067
4279
  webhook_url: string;
@@ -4090,7 +4302,17 @@ export interface operations {
4090
4302
  /**
4091
4303
  * @description Validation error. `bulk_too_large` is returned when the item count
4092
4304
  * exceeds the account plan's `max_bulk_size` cap (also surfaced as
4093
- * `max_bulk_size` on `GET /v1/account`).
4305
+ * `max_bulk_size` on `GET /v1/account`). `validation_error` is
4306
+ * returned when the request body contains an unrecognized key
4307
+ * anywhere in the top-level object, an `items[]` entry, or
4308
+ * `defaults` — all three reject unknown keys with a 422
4309
+ * `validation_error` whose `details` message names the offending
4310
+ * key, instead of silently discarding it. The two nested objects
4311
+ * do not accept the same field set: `device_scale_factor` is
4312
+ * `defaults`-only (rejected per item), and `duration`/`scenario`
4313
+ * are `items[]`-only (rejected under `defaults`). `metadata` is
4314
+ * valid both at the top level of the body and per item, but is
4315
+ * rejected with this same 422 if placed under `defaults`.
4094
4316
  */
4095
4317
  422: {
4096
4318
  headers: {
@@ -4131,7 +4353,8 @@ export interface operations {
4131
4353
  created_at: string;
4132
4354
  /** Format: date-time */
4133
4355
  completed_at: string | null;
4134
- total_credits_charged: number;
4356
+ /** @description Total credits billed for the job. Null until the job is billed. Fractional — credits are NUMERIC(10,2). */
4357
+ total_credits_charged: number | null;
4135
4358
  /** @description Null in GET responses (computed at submission time only). */
4136
4359
  estimated_credits: number | null;
4137
4360
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
@@ -4179,7 +4402,8 @@ export interface operations {
4179
4402
  created_at: string;
4180
4403
  /** Format: date-time */
4181
4404
  completed_at: string | null;
4182
- total_credits_charged: number;
4405
+ /** @description Total credits billed for the job. Null until the job is billed. Fractional — credits are NUMERIC(10,2). */
4406
+ total_credits_charged: number | null;
4183
4407
  /** @description Null in cancel responses (computed at submission time only). */
4184
4408
  estimated_credits: number | null;
4185
4409
  /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
@@ -4215,7 +4439,48 @@ export interface operations {
4215
4439
  [name: string]: unknown;
4216
4440
  };
4217
4441
  content: {
4218
- "application/json": Record<string, never>;
4442
+ "application/json": {
4443
+ /** @example bulk_01j9abc123 */
4444
+ bulk_id: string;
4445
+ /** @description Number of items in `items` (page size, not the job total). */
4446
+ total: number;
4447
+ /** @description Heterogeneous capture items discriminated by `type`. Fields outside the common set are present only for the matching `type`. */
4448
+ items: {
4449
+ /** @enum {string} */
4450
+ type: "screenshot" | "recording" | "scrape";
4451
+ /** @description Prefixed id — `ss_` / `rec_` / `sc_` per `type`. */
4452
+ id: string;
4453
+ /** @enum {string} */
4454
+ status: "pending" | "processing" | "completed" | "failed" | "cancelled";
4455
+ /** Format: uri */
4456
+ url: string;
4457
+ credits_charged: number | null;
4458
+ error_code: string | null;
4459
+ error_message: string | null;
4460
+ /** Format: date-time */
4461
+ created_at: string;
4462
+ /** Format: date-time */
4463
+ completed_at: string | null;
4464
+ /** @description `type: screenshot` only. Presigned for completed rows with a storage key; raw image_url otherwise. */
4465
+ image_url?: string | null;
4466
+ /** @description `type: screenshot` and `type: scrape` only. */
4467
+ page_title?: string | null;
4468
+ /** @description `type: recording` only. */
4469
+ format?: string;
4470
+ /** @description `type: recording` only. */
4471
+ video_url?: string | null;
4472
+ /** @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. */
4473
+ content_url?: string | null;
4474
+ /** @description `type: scrape` only. */
4475
+ content_type?: string | null;
4476
+ /** @description `type: scrape` only. */
4477
+ content_length?: number | null;
4478
+ /** @description `type: scrape` only. Always null in bulk listings — fetch the body via `markdown_url`. */
4479
+ markdown?: string | null;
4480
+ /** @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. */
4481
+ markdown_url?: string | null;
4482
+ }[];
4483
+ };
4219
4484
  };
4220
4485
  };
4221
4486
  };
@@ -4524,6 +4789,15 @@ export interface operations {
4524
4789
  "application/json": components["schemas"]["Error"];
4525
4790
  };
4526
4791
  };
4792
+ /** @description Rate limit (`rate_limited`) or concurrency limit (`concurrency_limit`) exceeded. Carries a `Retry-After` header — seconds derived from the same clock as `X-RateLimit-Reset` for the rate-limit variant, a fixed small back-off for the concurrency variant. */
4793
+ 429: {
4794
+ headers: {
4795
+ [name: string]: unknown;
4796
+ };
4797
+ content: {
4798
+ "application/json": components["schemas"]["Error"];
4799
+ };
4800
+ };
4527
4801
  };
4528
4802
  };
4529
4803
  getSitemap: {
@@ -4563,6 +4837,15 @@ export interface operations {
4563
4837
  "application/json": components["schemas"]["Error"];
4564
4838
  };
4565
4839
  };
4840
+ /** @description The id path segment is not a well-formed sitemap job id (genuinely malformed — a well-formed-but-absent id returns 404, not 422; see the Inverse case in issue */
4841
+ 422: {
4842
+ headers: {
4843
+ [name: string]: unknown;
4844
+ };
4845
+ content: {
4846
+ "application/json": components["schemas"]["Error"];
4847
+ };
4848
+ };
4566
4849
  };
4567
4850
  };
4568
4851
  createSearch: {
@@ -4656,7 +4939,7 @@ export interface operations {
4656
4939
  /** Format: uri */
4657
4940
  url: string;
4658
4941
  /** @description Short text excerpt for the result. Present for `web` and `news` results; omitted for `images` results. */
4659
- snippet: string;
4942
+ snippet?: string;
4660
4943
  /** @description Published date of the result. For `web` and `news` results the key is always present but is `null` when the provider reports no date; omitted entirely for `images` results. */
4661
4944
  date?: string | null;
4662
4945
  /** @description Publisher / source name. Present for `news` and `images` results, when the provider reports one. */
@@ -4710,7 +4993,7 @@ export interface operations {
4710
4993
  "application/json": components["schemas"]["Error"];
4711
4994
  };
4712
4995
  };
4713
- /** @description Rate limit exceeded. */
4996
+ /** @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. */
4714
4997
  429: {
4715
4998
  headers: {
4716
4999
  [name: string]: unknown;
@@ -4984,10 +5267,10 @@ export interface operations {
4984
5267
  /** @description Plan base price in cents. */
4985
5268
  plan_price_cents: number;
4986
5269
  /**
4987
- * @description Derived plan category. "payg" for pay-as-you-go plans, "free" for the free tier, "subscription" for all others.
5270
+ * @description Derived plan category. "payg" for pay-as-you-go plans, "subscription" for all recurring paid plans.
4988
5271
  * @enum {string}
4989
5272
  */
4990
- plan_type: "payg" | "free" | "subscription";
5273
+ plan_type: "payg" | "subscription";
4991
5274
  /** @description Total top-up spend in cents for this billing period. Present only in dual/bytes billing mode. */
4992
5275
  topup_spent_cents?: number;
4993
5276
  /** @description Remaining top-up bytes: max(0, topup_bytes − max(0, bytes_used − included_bytes − rollover_bytes)). Present only in dual/bytes billing mode. */
@@ -5192,7 +5475,7 @@ export interface operations {
5192
5475
  error_message?: string | null;
5193
5476
  /** @description Prefixed key id (ak_) that issued the request. */
5194
5477
  api_key_id?: string | null;
5195
- /** @description Stored content/image/video URL, if any. */
5478
+ /** @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. */
5196
5479
  artifact_url?: string | null;
5197
5480
  /** @description The original request options. */
5198
5481
  options?: {
@@ -5262,6 +5545,8 @@ export interface operations {
5262
5545
  requestBody: {
5263
5546
  content: {
5264
5547
  "application/json": {
5548
+ /** @enum {string} */
5549
+ purpose: "payment_method_update" | "invoice_history" | "subscription_cancel";
5265
5550
  /** Format: uri */
5266
5551
  return_url: string;
5267
5552
  };
@@ -5289,6 +5574,15 @@ export interface operations {
5289
5574
  "application/json": components["schemas"]["Error"];
5290
5575
  };
5291
5576
  };
5577
+ /** @description Cancellation disclosure revision is absent or stale. */
5578
+ 409: {
5579
+ headers: {
5580
+ [name: string]: unknown;
5581
+ };
5582
+ content: {
5583
+ "application/json": components["schemas"]["Error"];
5584
+ };
5585
+ };
5292
5586
  };
5293
5587
  };
5294
5588
  registerPayg: {
@@ -5488,23 +5782,8 @@ export interface operations {
5488
5782
  };
5489
5783
  };
5490
5784
  responses: {
5491
- /** @description Successful response. */
5492
- 200: {
5493
- headers: {
5494
- [name: string]: unknown;
5495
- };
5496
- content: {
5497
- "application/json": {
5498
- cancelled: boolean;
5499
- /** @enum {string} */
5500
- refund: "prorated";
5501
- /** Format: date-time */
5502
- grace_period_expires_at: string;
5503
- };
5504
- };
5505
- };
5506
- /** @description No subscription or already cancelled. */
5507
- 400: {
5785
+ /** @description Cancellation moved to hosted Billing Portal. */
5786
+ 410: {
5508
5787
  headers: {
5509
5788
  [name: string]: unknown;
5510
5789
  };
@@ -5876,6 +6155,21 @@ export interface operations {
5876
6155
  };
5877
6156
  content?: never;
5878
6157
  };
6158
+ /**
6159
+ * @description Bad request. Returned when the request body exceeds this
6160
+ * endpoint's 256 KB size limit (bespoke `{ error }` body, not the
6161
+ * unified envelope — see the endpoint description).
6162
+ */
6163
+ 400: {
6164
+ headers: {
6165
+ [name: string]: unknown;
6166
+ };
6167
+ content: {
6168
+ "application/json": {
6169
+ error?: string;
6170
+ };
6171
+ };
6172
+ };
5879
6173
  };
5880
6174
  };
5881
6175
  listWebhookDeliveries: {
@@ -5929,6 +6223,18 @@ export interface operations {
5929
6223
  "application/json": components["schemas"]["WebhookDeliveryResponse"];
5930
6224
  };
5931
6225
  };
6226
+ /**
6227
+ * @description Bad request. Returned when the request body exceeds this
6228
+ * endpoint's size limit; the error code is `request_too_large`.
6229
+ */
6230
+ 400: {
6231
+ headers: {
6232
+ [name: string]: unknown;
6233
+ };
6234
+ content: {
6235
+ "application/json": components["schemas"]["Error"];
6236
+ };
6237
+ };
5932
6238
  /** @description Delivery not found or not in a retryable state. */
5933
6239
  404: {
5934
6240
  headers: {
@@ -6145,6 +6451,15 @@ export interface operations {
6145
6451
  "application/json": components["schemas"]["Error"];
6146
6452
  };
6147
6453
  };
6454
+ /** @description Rate limit exceeded (`rate_limited`) — the Clerk-session 60-request/60-second per-user window. Carries a `Retry-After` header derived from the same clock as the window reset. */
6455
+ 429: {
6456
+ headers: {
6457
+ [name: string]: unknown;
6458
+ };
6459
+ content: {
6460
+ "application/json": components["schemas"]["Error"];
6461
+ };
6462
+ };
6148
6463
  };
6149
6464
  };
6150
6465
  updateMe: {
@@ -6181,6 +6496,15 @@ export interface operations {
6181
6496
  "application/json": components["schemas"]["Error"];
6182
6497
  };
6183
6498
  };
6499
+ /** @description Rate limit exceeded (`rate_limited`) — the Clerk-session 60-request/60-second per-user window. Carries a `Retry-After` header derived from the same clock as the window reset. */
6500
+ 429: {
6501
+ headers: {
6502
+ [name: string]: unknown;
6503
+ };
6504
+ content: {
6505
+ "application/json": components["schemas"]["Error"];
6506
+ };
6507
+ };
6184
6508
  };
6185
6509
  };
6186
6510
  requestEmailChange: {
@@ -6244,6 +6568,15 @@ export interface operations {
6244
6568
  "application/json": components["schemas"]["Error"];
6245
6569
  };
6246
6570
  };
6571
+ /** @description Rate limit exceeded (`rate_limited`) — the Clerk-session 60-request/60-second per-user window. Carries a `Retry-After` header derived from the same clock as the window reset. */
6572
+ 429: {
6573
+ headers: {
6574
+ [name: string]: unknown;
6575
+ };
6576
+ content: {
6577
+ "application/json": components["schemas"]["Error"];
6578
+ };
6579
+ };
6247
6580
  };
6248
6581
  };
6249
6582
  removeMember: {
@@ -6387,6 +6720,15 @@ export interface operations {
6387
6720
  "application/json": components["schemas"]["Error"];
6388
6721
  };
6389
6722
  };
6723
+ /** @description Rate limit exceeded (`rate_limited`) — the Clerk-session 60-request/60-second per-user window. Carries a `Retry-After` header derived from the same clock as the window reset. */
6724
+ 429: {
6725
+ headers: {
6726
+ [name: string]: unknown;
6727
+ };
6728
+ content: {
6729
+ "application/json": components["schemas"]["Error"];
6730
+ };
6731
+ };
6390
6732
  };
6391
6733
  };
6392
6734
  createInvite: {
@@ -6443,6 +6785,15 @@ export interface operations {
6443
6785
  "application/json": components["schemas"]["Error"];
6444
6786
  };
6445
6787
  };
6788
+ /** @description Rate limit exceeded (`rate_limited`) — the Clerk-session 60-request/60-second per-user window. Carries a `Retry-After` header derived from the same clock as the window reset. */
6789
+ 429: {
6790
+ headers: {
6791
+ [name: string]: unknown;
6792
+ };
6793
+ content: {
6794
+ "application/json": components["schemas"]["Error"];
6795
+ };
6796
+ };
6446
6797
  };
6447
6798
  };
6448
6799
  acceptInvite: {