@hunt-labs/bytekit-sdk 0.10.0 → 0.11.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.
package/CHANGELOG.md CHANGED
@@ -10,6 +10,80 @@ today, see [README.md](./README.md), which remains the authoritative usage guide
10
10
 
11
11
  ## [Unreleased]
12
12
 
13
+ ## [0.11.0] - 2026-09-14
14
+
15
+ ### Added
16
+
17
+ - **`solve_challenge` on `scrape.create` (#4447).** `ScrapeOpts` now carries
18
+ `solve_challenge?: boolean`, and the generated `ScrapeRequest` schema type carries the field
19
+ with its server default `false`. When `true`,
20
+ the scrape attempts to clear a Cloudflare challenge; success is not guaranteed. It is billed
21
+ as a normal browser render. A scrape that omits the option sends no `solve_challenge` key,
22
+ so existing calls are unchanged on the wire.
23
+ - **`credits_scrape` on the usage response types (#4452).** The generated `GET /v1/usage`
24
+ response type and each `GET /v1/usage/daily` data item now carry `credits_scrape: number`:
25
+ credits drawn under the scrape usage source, such as `/v1/schema` extractions. The gateway
26
+ always charged this bucket but never returned it, so the published per-source credit fields
27
+ could not add up to `credits_used`.
28
+
29
+ ### Changed
30
+
31
+ - **Internal `GET /v1/bulk` is cursor-paginated and its 100-job cap is gone (#4508).** The
32
+ generated `listBulk` types record a changed response shape: the operation used to return a
33
+ bare array of at most the 100 newest jobs, and now returns the same page envelope
34
+ `GET /v1/monitors` does, `{ data, next_cursor, has_more }`, plus `limit` and `cursor` query
35
+ parameters (`limit` is 1 to 100, default 25). A `status` filter and a `cursor` combine in
36
+ one request: `status` narrows the set and the cursor addresses a position inside it. The
37
+ operation's summary also no longer says "in-flight", which was wrong — it has always
38
+ returned jobs of every status, `cancelled` included. This is a breaking change to the wire
39
+ shape of an `x-sdk-scope: internal` operation; no SDK method calls it, so no published
40
+ method signature moves.
41
+ - **`GET /v1/logs` `billing_multiplier` is the bandwidth factor, not a credit count (#4469).**
42
+ The generated logs-row type records the changed meaning of a public field: the value is now
43
+ `billable_bytes` / `raw_bytes` rounded to 2 decimal places — the factor the request settled
44
+ at, carrying the endpoint, cache-hit and clean-markdown factors, and the flat 1.5 Phase-1
45
+ factor on screenshots and recordings. It used to be the row's persisted `credits_charged`,
46
+ an account credit count charged per capture option, so two screenshots billed at the same
47
+ 1.5 factor reported `2` and `1`. The 2 decimal places are load-bearing rather than
48
+ cosmetic: `billable_bytes` is itself rounded, so an odd byte basis would otherwise surface
49
+ as `1.500001943158721` instead of `1.5` on roughly half of all such rows. Every factor the
50
+ field can report is a multiple of 0.25, so 2 places is exact for any basis of 100 bytes or
51
+ more, and `raw_bytes` × `billing_multiplier` rounded to the nearest byte still reproduces
52
+ `billable_bytes`. The `billable_bytes` doc comment therefore no longer says it is NOT
53
+ `raw_bytes` × `billing_multiplier`. The field is also null on more rows than before: a
54
+ search or webhook row has no byte basis, a capture whose Phase 1 was skipped has a zero one,
55
+ and a capture old enough to predate the Phase-1 basis being recorded has none at all. One
56
+ residual is documented rather than fixed: a markdown `/v1/fetch` row completed before the
57
+ billing decomposition was recorded reports 1.0 where settlement charged 1.5, because nothing
58
+ on such a row distinguishes it. The type shapes are unchanged (`number | null`), and no SDK
59
+ method calls this endpoint.
60
+ - **An all-null `/v1/schema` extraction your schema allows is validated again (#4490).** The
61
+ generated `/v1/schema` 200 response type records the exception to #4455's rule: an output
62
+ whose every leaf is `null` still arrives `validated: true` with the object intact, and is
63
+ charged, when the schema you sent declares `"null"` in the `type` union of every leaf the
64
+ output returned as `null`. Only that form counts — `nullable: true`, an `enum` containing
65
+ `null` and `const: null` do not, and a response that is itself `null` rather than an object is
66
+ never accepted however the root is declared. Everything else stays the #4455 miss. The `data`
67
+ doc comment now also states the other half: a `validated: true` response always carries an
68
+ object, never `null`. The type shapes are unchanged; only their doc comments moved.
69
+ - **An all-null `/v1/schema` extraction is reported, not validated (#4455).** The generated
70
+ `/v1/schema` 200 response type documents a new additive warning code, `empty_extraction`: a
71
+ schema-valid output whose every leaf is `null` now arrives with `data: null` and
72
+ `validated: false`, and is not charged the per-request credits. Previously it arrived as
73
+ `validated: true` with the all-null object and no warning. The `data` and `validated` doc
74
+ comments now also say that every `validated: false` response carries `data: null`; the old
75
+ comment claimed exhausted retries returned the last raw output, which the API never did. The
76
+ type shapes are unchanged; only their doc comments moved.
77
+ - **An inline `POST /v1/scrape` failure is documented with a persisted `id` (#4454).** The
78
+ gateway now records a sync scrape that ends `upstream_error` or `blocked` as a failed scrape
79
+ job, so its `failed` envelope carries that job's `sc_` id instead of `null`, `scrape.get(id)`
80
+ returns the same envelope, and the request appears in the dashboard Logs. The generated
81
+ `createScrape` 200 and `ScrapeErrorEnvelope` doc comments and the `scrape.create` doc comment
82
+ no longer say `id: null`. The type shapes are unchanged (`id` stays `string | null`), and
83
+ `scrape.create` still throws `ByteKitError` on that envelope exactly as before.
84
+ - **Internal `GET /v1/logs` types list search and webhook rows (#4460).** Both `endpoint` enums
85
+ add `search` and `webhook`; a row's `source` is now `string | null`. No SDK method calls it.
86
+
13
87
  ## [0.10.0] - 2026-09-11
14
88
 
15
89
  ### Changed
package/dist/client.js CHANGED
@@ -221,7 +221,7 @@ function parseJsonBody(text) {
221
221
  * The gateway used to report a terminal upstream fetch failure as HTTP 503, and
222
222
  * `!response.ok` in {@link ByteKit.send} was this SDK's only failure seam. Now that the
223
223
  * same outcome arrives as an intentional 200 — a definitive upstream result is not a
224
- * transport error, and `id` is `null` because the fetch failed before any job existed —
224
+ * transport error, and `id` names the failed job the gateway recorded it as —
225
225
  * that seam alone would let the failure resolve like a success and silence every caller's
226
226
  * `catch`. This restores the exception integrators already write code for, with the
227
227
  * envelope's own `code` and `message`.
@@ -202,7 +202,7 @@ export interface paths {
202
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
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
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.
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 is recorded as a failed job, so its envelope normally carries that job's `id` and `GET /v1/scrape/{id}` returns the same envelope; if recording the failed job itself fails, the envelope still arrives on the same 200 with `id` set to `null` and there is nothing to poll. A failure a held render reaches carries that render's real `id`. Either way the request transfers no billable bytes and is charged nothing.
206
206
  *
207
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.
208
208
  */
@@ -391,9 +391,13 @@ export interface paths {
391
391
  cookie?: never;
392
392
  };
393
393
  /**
394
- * List in-flight bulk jobs
395
- * @description Returns the caller's bulk jobs, most recent first. Optionally filter
396
- * to a single status; when omitted, jobs of every status are returned.
394
+ * List bulk jobs
395
+ * @description Returns the caller's bulk jobs, most recent first, one cursor-paginated
396
+ * page at a time. Optionally filter to a single status; when omitted, jobs
397
+ * of every status are returned. `status` narrows the set and the cursor
398
+ * addresses a position inside that already-ordered, already-filtered set,
399
+ * so the two can be combined in one request. Follow `next_cursor` while
400
+ * `has_more` is true.
397
401
  */
398
402
  get: operations["listBulk"];
399
403
  put?: never;
@@ -716,7 +720,7 @@ export interface paths {
716
720
  };
717
721
  /**
718
722
  * Get the unified request log feed
719
- * @description Returns a unified, newest-first feed of the account's capture requests across scrape, fetch, screenshots, and recordings, for the dashboard /logs screen. Cursor-paginated; default range is the last 30 days, max 366 days.
723
+ * @description Returns a unified, newest-first feed of the account's requests across scrape, fetch, screenshots, recordings and search, plus webhook delivery attempts, for the dashboard /logs screen. Monitor runs are listed as the scrape and screenshots rows they produce (`source: monitor`). Cursor-paginated; default range is the last 30 days, max 366 days.
720
724
  */
721
725
  get: operations["getLogs"];
722
726
  put?: never;
@@ -795,11 +799,13 @@ export interface paths {
795
799
  get?: never;
796
800
  put?: never;
797
801
  /**
798
- * One-time bandwidth purchase
799
- * @description Creates a hosted Stripe Checkout session for a bandwidth top-up and
800
- * returns its URL. The caller redirects the user to `checkout_url`; the
801
- * balance is credited asynchronously by the `payment_intent.succeeded`
802
- * webhook once payment completes.
802
+ * One-time dollar deposit
803
+ * @description Creates a hosted Stripe Checkout session for a deposit into the account's
804
+ * USD balance and returns its URL. The caller redirects the user to
805
+ * `checkout_url`; the balance is credited asynchronously by the
806
+ * `payment_intent.succeeded` webhook once payment completes. The balance
807
+ * never expires and pays for usage beyond the included allowance, for
808
+ * bandwidth and search credits alike, at the plan's rate when it is used.
803
809
  */
804
810
  post: operations["createTopup"];
805
811
  delete?: never;
@@ -808,29 +814,6 @@ export interface paths {
808
814
  patch?: never;
809
815
  trace?: never;
810
816
  };
811
- "/v1/billing/credit-topup": {
812
- parameters: {
813
- query?: never;
814
- header?: never;
815
- path?: never;
816
- cookie?: never;
817
- };
818
- get?: never;
819
- put?: never;
820
- /**
821
- * One-time credit purchase
822
- * @description Creates a hosted Stripe Checkout session for a credit top-up and returns
823
- * its URL. The caller redirects the user to `checkout_url`; credits are
824
- * added asynchronously by the `payment_intent.succeeded` webhook once
825
- * payment completes.
826
- */
827
- post: operations["createCreditTopup"];
828
- delete?: never;
829
- options?: never;
830
- head?: never;
831
- patch?: never;
832
- trace?: never;
833
- };
834
817
  "/v1/billing/cancel": {
835
818
  parameters: {
836
819
  query?: never;
@@ -924,8 +907,8 @@ export interface paths {
924
907
  get?: never;
925
908
  /**
926
909
  * Configure auto-topup
927
- * @description Enable or disable automatic bandwidth top-ups. When enabling,
928
- * threshold_bytes, amount_bytes, and monthly_cap_cents must all be present;
910
+ * @description Enable or disable automatic top-ups of the USD balance. When enabling,
911
+ * threshold_cents, amount_cents, and monthly_cap_cents must all be present;
929
912
  * monthly_cap_cents may be null, which means no monthly cap.
930
913
  */
931
914
  put: operations["updateAutoTopup"];
@@ -1738,6 +1721,11 @@ export interface components {
1738
1721
  * @default false
1739
1722
  */
1740
1723
  mobile: boolean;
1724
+ /**
1725
+ * @description Attempts to clear a Cloudflare challenge; success is not guaranteed. Billed as a normal browser render.
1726
+ * @default false
1727
+ */
1728
+ solve_challenge: boolean;
1741
1729
  /**
1742
1730
  * @description When true (default), base64-encoded `data:` image sources are stripped from the HTML before markdown conversion. Set to false to preserve base64 images in the pipeline output. Does not affect `raw`, which always returns the original source unchanged.
1743
1731
  * @default true
@@ -1980,7 +1968,7 @@ export interface components {
1980
1968
  cache_age_s?: number;
1981
1969
  };
1982
1970
  /**
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`.
1971
+ * @description The canonical terminal failure payload. It is returned inline on a `POST /v1/scrape` that fails upstream (HTTP 200, `id` naming the failed job it is recorded as, or `null` in the rare case that recording itself failed), by `GET /v1/scrape/{id}` once a queued job has failed, and delivered to subscribers of `failed` with `X-ByteKit-Event: scrape.failed`.
1984
1972
  * @example {
1985
1973
  * "schema_version": 1,
1986
1974
  * "status": "failed",
@@ -2671,8 +2659,8 @@ export interface components {
2671
2659
  };
2672
2660
  auto_topup: {
2673
2661
  enabled: boolean;
2674
- threshold_bytes: number;
2675
- amount_bytes: number;
2662
+ threshold_cents: number;
2663
+ amount_cents: number;
2676
2664
  monthly_cap_cents: number;
2677
2665
  };
2678
2666
  /** Format: date-time */
@@ -2795,24 +2783,24 @@ export interface components {
2795
2783
  used_bytes: number;
2796
2784
  limit_bytes: number;
2797
2785
  remaining_bytes: number;
2798
- /** @description Total spendable bytes remaining across purchased top-up and starter-grant lots, after active refund reservations. */
2786
+ /** @description Total spendable top-up bytes: the USD balance's current-plan estimate (`purchased_topup_bytes`) plus the starter grant. */
2799
2787
  topup_bytes: number;
2800
- /** @description Bytes remaining in purchased top-up lots, after active refund reservations. Starter-grant bytes are excluded. */
2788
+ /** @description Estimate of the bytes the USD balance buys at the current plan's rate, after amounts held by open refunds. Not a separate balance: it changes when the plan changes. Starter-grant bytes are excluded. */
2801
2789
  purchased_topup_bytes: number;
2802
- /** @description Bytes remaining in starter-grant lots, after active refund reservations. Purchased top-up bytes are excluded. */
2790
+ /** @description Bytes remaining in starter-grant lots, after active refund reservations. The USD balance estimate is excluded. */
2803
2791
  granted_topup_bytes: number;
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. */
2792
+ /** @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 the USD balance, then the one-time starter grant. */
2805
2793
  rollover_bytes: number;
2806
2794
  };
2807
2795
  CreditBalance: {
2808
2796
  used: number;
2809
2797
  limit: number;
2810
2798
  remaining: number;
2811
- /** @description Total spendable credits remaining across purchased top-up and starter-grant lots, after active refund reservations. */
2799
+ /** @description Total spendable top-up credits: the USD balance's current-plan estimate (`purchased_topup_credits`) plus the starter grant. */
2812
2800
  topup_credits: number;
2813
- /** @description Credits remaining in purchased top-up lots, after active refund reservations. Starter-grant credits are excluded. */
2801
+ /** @description Estimate of the credits the USD balance buys at the current plan's rate, after amounts held by open refunds. Not a separate balance: it changes when the plan changes. Starter-grant credits are excluded. */
2814
2802
  purchased_topup_credits: number;
2815
- /** @description Credits remaining in starter-grant lots, after active refund reservations. Purchased top-up credits are excluded. */
2803
+ /** @description Credits remaining in starter-grant lots, after active refund reservations. The USD balance estimate is excluded. */
2816
2804
  granted_topup_credits: number;
2817
2805
  /** @description Always `0`. Search credits do not carry over between billing periods; the field is retained for contract stability and will not become non-zero without an announced plan change. */
2818
2806
  rollover_credits: number;
@@ -3600,7 +3588,7 @@ export interface operations {
3600
3588
  };
3601
3589
  };
3602
3590
  responses: {
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. */
3591
+ /** @description Scrape reached a terminal state and the body is that terminal envelope: `success` carrying content, or `failed` carrying the error envelope. Returned by the fast HTTP path in one round trip, and by a browser-path request without `async: true` once its render reaches a terminal state inside the hold window. A held render that ends in failure answers 200 with the same `failed` envelope `GET /v1/scrape/{id}` returns — narrow on `status` before reading the body. A definitive upstream outcome is a result, not a transport error: an unreachable host, a refused connection, or a target whose bot protection defeats every proxy tier all answer 200 with the `failed` envelope, never a 5xx. An inline failure is recorded as a failed job, so its envelope normally carries that job's `id` and polling it returns the same envelope; `id` is `null` only when recording the failed job itself failed. `error.http_status` is present only when a real upstream HTTP status is known. */
3604
3592
  200: {
3605
3593
  headers: {
3606
3594
  /** @description Stable scrape identifier (also present on the envelope as `id`). */
@@ -4615,6 +4603,9 @@ export interface operations {
4615
4603
  listBulk: {
4616
4604
  parameters: {
4617
4605
  query?: {
4606
+ limit?: components["parameters"]["LimitParam"];
4607
+ /** @description Pagination cursor from a previous response. */
4608
+ cursor?: components["parameters"]["CursorParam"];
4618
4609
  status?: "processing" | "completed" | "failed";
4619
4610
  };
4620
4611
  header?: never;
@@ -4630,27 +4621,31 @@ export interface operations {
4630
4621
  };
4631
4622
  content: {
4632
4623
  "application/json": {
4633
- /** @example bulk_01j9abc123 */
4634
- id: string;
4635
- /** @enum {string} */
4636
- status: "processing" | "completed" | "failed";
4637
- total: number;
4638
- completed: number;
4639
- failed: number;
4640
- /** Format: date-time */
4641
- created_at: string;
4642
- /** Format: date-time */
4643
- completed_at: string | null;
4644
- /** @description Total credits billed for the job. Null until the job is billed. Fractional — credits are NUMERIC(10,2). */
4645
- total_credits_charged: number | null;
4646
- /** @description Null in GET responses (computed at submission time only). */
4647
- estimated_credits: number | null;
4648
- /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
4649
- webhook_url: string;
4650
- }[];
4624
+ next_cursor: string | null;
4625
+ has_more: boolean;
4626
+ data: {
4627
+ /** @example bulk_01j9abc123 */
4628
+ id: string;
4629
+ /** @enum {string} */
4630
+ status: "processing" | "completed" | "failed";
4631
+ total: number;
4632
+ completed: number;
4633
+ failed: number;
4634
+ /** Format: date-time */
4635
+ created_at: string;
4636
+ /** Format: date-time */
4637
+ completed_at: string | null;
4638
+ /** @description Total credits billed for the job. Null until the job is billed. Fractional — credits are NUMERIC(10,2). */
4639
+ total_credits_charged: number | null;
4640
+ /** @description Null in GET responses (computed at submission time only). */
4641
+ estimated_credits: number | null;
4642
+ /** @description Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported) */
4643
+ webhook_url: string;
4644
+ }[];
4645
+ };
4651
4646
  };
4652
4647
  };
4653
- /** @description Validation error. Returned when `status` is not one of the documented values. */
4648
+ /** @description Validation error. Returned when `status` is not one of the documented values, or when `cursor` is not a cursor this endpoint issued. */
4654
4649
  422: {
4655
4650
  headers: {
4656
4651
  [name: string]: unknown;
@@ -5758,10 +5753,10 @@ export interface operations {
5758
5753
  };
5759
5754
  content: {
5760
5755
  "application/json": {
5761
- /** @description Extracted JSON conforming to the normalized schema, or `null` when the model returned a refusal. */
5756
+ /** @description Extracted JSON conforming to the normalized schema, or `null` when `validated` is `false` — see `validated` for the cases. A `validated: true` response always carries an object here, never `null`. */
5762
5757
  data: Record<string, never> | null;
5763
5758
  model: string;
5764
- /** @description `true` when the output passed Ajv re-validation; `false` when retries were exhausted (`data` carries the last raw output, with `extract_validation_failed` in `warnings`). */
5759
+ /** @description `true` when the output passed Ajv re-validation and at least one leaf is non-null. An all-null output is also `true` when your schema explicitly allows it: every leaf the output returned as `null` sits at a node whose `type` is a union containing `"null"` in the schema you sent (only that form counts — `nullable: true`, an `enum` containing `null` and `const: null` do not). An output that is itself `null` rather than an object is never accepted, whatever your root schema declares. `false` (with `data: null`) when the model refused (`model_refusal`), when retries were exhausted (`extract_validation_failed`, `exhausted_retries`), or when a schema-valid output has every leaf `null` and is not one the declaration above accepts (`empty_extraction`). The per-request credits are charged only for `true`. */
5765
5760
  validated: boolean;
5766
5761
  metrics: {
5767
5762
  scrape_ms: number;
@@ -5781,7 +5776,7 @@ export interface operations {
5781
5776
  /** @description True when markdown exceeded the LLM token budget and was tail-truncated. */
5782
5777
  truncated: boolean;
5783
5778
  };
5784
- /** @description Additive warning codes, e.g. `content_truncated`, `extract_validation_failed`, `exhausted_retries`, `model_refusal`. */
5779
+ /** @description Additive warning codes, e.g. `content_truncated`, `extract_validation_failed`, `exhausted_retries`, `model_refusal`, `empty_extraction`. */
5785
5780
  warnings: string[];
5786
5781
  };
5787
5782
  };
@@ -5888,6 +5883,8 @@ export interface operations {
5888
5883
  credits_single: number;
5889
5884
  credits_bulk: number;
5890
5885
  credits_monitor: number;
5886
+ /** @description Credits drawn under the scrape usage source this billing period, such as `/v1/schema` extractions. `credits_single`, `credits_bulk`, `credits_monitor`, `credits_scrape` and `credits_search` together sum to `credits_used`. */
5887
+ credits_scrape: number;
5891
5888
  /** @description Credits consumed by the search endpoint this billing period. Reported as a distinct line item, not folded into other per-source credit counts. */
5892
5889
  credits_search: number;
5893
5890
  credits_limit: number;
@@ -5905,7 +5902,7 @@ export interface operations {
5905
5902
  plan_type: "payg" | "subscription";
5906
5903
  /** @description Total top-up spend in cents for this billing period. Present only in dual/bytes billing mode. */
5907
5904
  topup_spent_cents?: number;
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. */
5905
+ /** @description Remaining top-up bytes: the current-plan estimate of what the USD balance buys plus the one-time starter grant, already net of any overage consumed against them. Equal to topup_bytes. Present only in dual/bytes billing mode. */
5909
5906
  topup_balance_bytes?: number;
5910
5907
  /** @description Days elapsed since period_start. */
5911
5908
  period_days_elapsed: number;
@@ -5915,13 +5912,13 @@ export interface operations {
5915
5912
  bytes_bulk: number;
5916
5913
  bytes_scrape: number;
5917
5914
  bytes_monitor: number;
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. */
5915
+ /** @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 the USD balance's current-plan byte estimate and the starter grant. The figure falls as they are consumed. */
5919
5916
  bytes_limit: number;
5920
5917
  /** @description Bytes still available across every active lot, after active refund reservations. */
5921
5918
  bytes_remaining: number;
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. */
5919
+ /** @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 the USD balance, then the one-time starter grant. */
5923
5920
  rollover_bytes: number;
5924
- /** @description Bytes remaining in purchased top-up and starter-grant lots. Subscription allowance is excluded. */
5921
+ /** @description The USD balance's current-plan byte estimate plus the starter grant. Subscription allowance is excluded. */
5925
5922
  topup_bytes: number;
5926
5923
  /** @description Total API requests in the current billing period. */
5927
5924
  request_count: number;
@@ -5967,6 +5964,8 @@ export interface operations {
5967
5964
  credits_single: number;
5968
5965
  credits_bulk: number;
5969
5966
  credits_monitor: number;
5967
+ /** @description Credits drawn under the scrape usage source on this day, such as `/v1/schema` extractions. */
5968
+ credits_scrape: number;
5970
5969
  /** @description Credits consumed by the search endpoint on this day. */
5971
5970
  credits_search: number;
5972
5971
  credits_total: number;
@@ -6057,12 +6056,12 @@ export interface operations {
6057
6056
  /** @description End date (YYYY-MM-DD), inclusive. Default today. */
6058
6057
  to?: string;
6059
6058
  /** @description Filter to a single endpoint kind. */
6060
- endpoint?: "scrape" | "fetch" | "screenshots" | "recordings";
6059
+ endpoint?: "scrape" | "fetch" | "screenshots" | "recordings" | "search" | "webhook";
6061
6060
  /** @description Filter by job outcome. */
6062
6061
  status?: "pending" | "processing" | "completed" | "failed";
6063
- /** @description Case-insensitive substring match on the request URL. */
6062
+ /** @description Case-insensitive substring match on the request URL — the search query on search rows and the target URL on webhook rows. */
6064
6063
  url?: string;
6065
- /** @description Filter by API key (prefixed ID, e.g. `ak_xxx`). The key must belong to the requesting account; cross-account keys return an empty feed. Resolves the account's playground key too. */
6064
+ /** @description Filter by API key (prefixed ID, e.g. `ak_xxx`). The key must belong to the requesting account; cross-account keys return an empty feed. Resolves the account's playground key too. Webhook delivery attempts are not issued by an API key, so this filter excludes them. */
6066
6065
  api_key?: string;
6067
6066
  /** @description Opaque pagination cursor from a prior response's `next_cursor`. */
6068
6067
  cursor?: string;
@@ -6083,30 +6082,35 @@ export interface operations {
6083
6082
  content: {
6084
6083
  "application/json": {
6085
6084
  data: {
6086
- /** @description Prefixed request id (sc_/ss_/rec_). */
6085
+ /** @description Prefixed request id (sc_/ss_/rec_/sr_/wh_). */
6087
6086
  id: string;
6088
- /** @enum {string} */
6089
- endpoint: "scrape" | "fetch" | "screenshots" | "recordings";
6090
- /** @description HTTP method. Not persisted; capture endpoints are POST (so this is always "POST"). /v1/fetch also accepts GET, but the stored row cannot distinguish it. */
6087
+ /**
6088
+ * @description The request kind. `webhook` rows are webhook delivery attempts ByteKit sent to your endpoint, not requests you made.
6089
+ * @enum {string}
6090
+ */
6091
+ endpoint: "scrape" | "fetch" | "screenshots" | "recordings" | "search" | "webhook";
6092
+ /** @description HTTP method. Not persisted; capture and search endpoints are POST, and webhook deliveries are sent as POST (so this is always "POST"). /v1/fetch also accepts GET, but the stored row cannot distinguish it. */
6091
6093
  method: string;
6094
+ /** @description The request URL. On a search row this is the search query (empty once the retention window has redacted it); on a webhook row it is the delivery target URL. */
6092
6095
  url: string;
6093
6096
  final_url?: string | null;
6094
6097
  /**
6095
- * @description Job outcome.
6098
+ * @description Job outcome. On a webhook row: `completed` = delivered, `processing` = a failed attempt that will be retried, `failed` = retries exhausted, `pending` = not yet delivered or failed (an attempt may be in flight).
6096
6099
  * @enum {string}
6097
6100
  */
6098
6101
  status: "pending" | "processing" | "completed" | "failed";
6099
- /** @description Upstream target HTTP status; scrape/fetch only. */
6102
+ /** @description Upstream target HTTP status on scrape/fetch rows; the HTTP status your endpoint answered on webhook rows. null on every other row. */
6100
6103
  status_code?: number | null;
6101
6104
  /** @description Raw upstream bytes the request carried (the billing base before the multiplier). null while pending/failed. */
6102
6105
  raw_bytes?: number | null;
6103
- /** @description The bytes this request was BILLED — the same amount its own response reported in `X-Billable-Bytes`. For a scrape or fetch request this is the settled decomposition replayed as it was recorded at completion, so it already carries every factor that applied: the endpoint factor (`scrape` 1.0, `scrape_md` 1.5, `fetch` 1.0, `fetch_md` 1.5, a monitor run 1.0), the cache-hit ×0.5, and the clean-markdown ×3. Screenshots and recordings are `raw_bytes` × the fixed 1.5 Phase-1 render factor whatever capture options they carried — capture billing composes no discount factor, so that product is exact. It is NOT `raw_bytes` × `billing_multiplier`: that field reports a CREDIT count, a different quantity from the byte factors above, and on a recordings row their product is not bytes at all. One residual: a scrape or fetch row completed before the decomposition was recorded is reconstructed from its endpoint and cache-hit factors, which leaves a markdown `/v1/fetch` request of that vintage reported at 1.0 rather than 1.5 — nothing on such a row distinguishes it. That population ages out of this feed's retention window and is not backfilled. null while pending/failed (the row has no byte basis yet). */
6106
+ /** @description The bytes this request was BILLED — the same amount its own response reported in `X-Billable-Bytes`. For a scrape or fetch request this is the settled decomposition replayed as it was recorded at completion, so it already carries every factor that applied: the endpoint factor (`scrape` 1.0, `scrape_md` 1.5, `fetch` 1.0, `fetch_md` 1.5, a monitor run 1.0), the cache-hit ×0.5, and the clean-markdown ×3. Screenshots and recordings are `raw_bytes` × the fixed 1.5 Phase-1 render factor whatever capture options they carried — capture billing composes no discount factor, so that product is exact. This is the settled amount itself, never a product reconstructed from another field: `billing_multiplier` below is DERIVED from it (that field is this value over `raw_bytes`), so the dependency runs this way and not the other. One residual: a scrape or fetch row completed before the decomposition was recorded is reconstructed from its endpoint and cache-hit factors, which leaves a markdown `/v1/fetch` request of that vintage reported at 1.0 rather than 1.5 — nothing on such a row distinguishes it. That population ages out of this feed's retention window and is not backfilled. null while pending/failed (the row has no byte basis yet). */
6104
6107
  billable_bytes?: number | null;
6105
- /** @description BASE billing multiplier persisted for this request — the settled `credits_charged` factor. It is NOT what `billable_bytes` above is derived from: that field reports settled BYTES, and multiplying `raw_bytes` by this credit count does not give the amount billed. Its scale is not uniform and is not a rate you can carry from one row to another: each endpoint persists its own credit unit, and the single and bulk paths of the same endpoint may persist different factors for identical options. Read this as the factor this one row settled at, and see https://bytekit.com/docs/billing/credits for what each endpoint charges. This is a LOGS ROW field and is NOT the scrape response envelope field — the envelope carries no flat `billing_multiplier` at all; its billing surface is the `billing` node (see BillingNode). This row reports only the base settled factor, so it can differ from `billing.multiplier` and from the X-Billing-Multiplier response header, both of which report the composed real-endpoint value. null while pending/failed. */
6108
+ /** @description The bandwidth factor this request settled at, DERIVED from the two fields above as `billable_bytes` / `raw_bytes`, ROUNDED TO 2 DECIMAL PLACES. It carries every factor that applied to the settled amount, composed: the endpoint factor, the cache-hit ×0.5 and the clean-markdown ×3 on a scrape or fetch row, and the flat 1.5 Phase-1 render factor on every screenshot and recording row whatever capture options it carried. Every factor reachable that way is a multiple of 0.25 (0.5, 0.75, 1, 1.5, 2.25, 3, 4.5), so 2 places reports each of them exactly on any basis of 100 bytes or more. The rounding is there because `billable_bytes` is itself rounded, which on an odd basis would otherwise surface here as 1.500001943158721 rather than 1.5. `raw_bytes` × `billing_multiplier`, rounded to the nearest byte, reproduces `billable_bytes` at every basis. CHANGED: this field used to report the row's persisted `credits_charged` — an account CREDIT count on a per-endpoint scale, not a bandwidth factor. On a screenshot that count is charged per capture option (`full_page`, `mobile`), so two captures billed at the same 1.5 factor reported different multipliers. See https://bytekit.com/docs/billing/credits for the credit counts each endpoint charges, which this field no longer reports. This is a LOGS ROW field and is NOT the scrape response envelope field — the envelope carries no flat `billing_multiplier` at all; its billing surface is the `billing` node (see BillingNode). It reports the same composed value as `billing.multiplier` and the X-Billing-Multiplier response header wherever `billable_bytes` is exact, which is every row but one: the residual described above for `billable_bytes`, a markdown `/v1/fetch` request completed before the decomposition was recorded, is reconstructed at 1.0 where settlement charged 1.5, and this field reports that same 1.0. null where the row has no factor to report: while pending/failed; on a search or webhook row (neither has a byte basis); where the basis is zero because Phase 1 was skipped or failed and the request billed nothing; and on a completed screenshot or recording old enough that no Phase-1 basis was ever recorded for it, which reports null rather than claiming a real past charge was nothing. */
6106
6109
  billing_multiplier?: number | null;
6110
+ /** @description Request duration in milliseconds; on a webhook row, how long your endpoint took to answer the latest attempt. */
6107
6111
  duration_ms?: number | null;
6108
- /** @description How the request originated (single/bulk/monitor). */
6109
- source?: string;
6112
+ /** @description How the request originated (single/bulk/monitor). null on search and webhook rows. */
6113
+ source?: string | null;
6110
6114
  error_code?: string | null;
6111
6115
  error_message?: string | null;
6112
6116
  /** @description Prefixed key id (ak_) that issued the request. */
@@ -6272,81 +6276,10 @@ export interface operations {
6272
6276
  content: {
6273
6277
  "application/json": {
6274
6278
  /**
6275
- * @description Bytes to purchase. Allowed tiers — 5, 25, 50, 75, 100 GB (1 GB = 1,000,000,000 bytes).
6279
+ * @description Amount to deposit, in US cents. Allowed amounts — $10, $25, $50, $100, $500. Charged exactly; the plan rate prices usage, not the deposit.
6276
6280
  * @enum {integer}
6277
6281
  */
6278
- bytes: 5000000000 | 25000000000 | 50000000000 | 75000000000 | 100000000000;
6279
- /**
6280
- * Format: uri
6281
- * @description Redirect target after a completed Checkout.
6282
- */
6283
- success_url: string;
6284
- /**
6285
- * Format: uri
6286
- * @description Redirect target when the user abandons Checkout.
6287
- */
6288
- cancel_url: string;
6289
- };
6290
- };
6291
- };
6292
- responses: {
6293
- /** @description Hosted Checkout session created. */
6294
- 200: {
6295
- headers: {
6296
- [name: string]: unknown;
6297
- };
6298
- content: {
6299
- "application/json": {
6300
- /** Format: uri */
6301
- checkout_url: string;
6302
- session_id: string;
6303
- };
6304
- };
6305
- };
6306
- /** @description No customer or free plan. */
6307
- 400: {
6308
- headers: {
6309
- [name: string]: unknown;
6310
- };
6311
- content: {
6312
- "application/json": components["schemas"]["Error"];
6313
- };
6314
- };
6315
- /** @description Validation error (missing/invalid fields). */
6316
- 422: {
6317
- headers: {
6318
- [name: string]: unknown;
6319
- };
6320
- content: {
6321
- "application/json": components["schemas"]["Error"];
6322
- };
6323
- };
6324
- /** @description Stripe error creating the Checkout session. */
6325
- 502: {
6326
- headers: {
6327
- [name: string]: unknown;
6328
- };
6329
- content: {
6330
- "application/json": components["schemas"]["Error"];
6331
- };
6332
- };
6333
- };
6334
- };
6335
- createCreditTopup: {
6336
- parameters: {
6337
- query?: never;
6338
- header?: never;
6339
- path?: never;
6340
- cookie?: never;
6341
- };
6342
- requestBody: {
6343
- content: {
6344
- "application/json": {
6345
- /**
6346
- * @description Credits to purchase. Allowed tiers — 1k, 10k, 25k, 50k, 100k.
6347
- * @enum {integer}
6348
- */
6349
- credits: 1000 | 10000 | 25000 | 50000 | 100000;
6282
+ amount_cents: 1000 | 2500 | 5000 | 10000 | 50000;
6350
6283
  /**
6351
6284
  * Format: uri
6352
6285
  * @description Redirect target after a completed Checkout.
@@ -6641,10 +6574,17 @@ export interface operations {
6641
6574
  included_bytes?: number;
6642
6575
  /** @description Number of automatic top-up transactions (bandwidth and credit) that have been triggered in the current calendar month. Includes both pending and completed transactions. */
6643
6576
  triggers_this_month?: number;
6577
+ /** @description The account's USD top-up balance. It never expires and is spent on usage beyond the included allowance, at the rate of the plan in force when the usage happens. */
6578
+ usd_balance: {
6579
+ /** @description Balance in whole US cents, rounded down. Can be negative when usage settled after the balance ran out. */
6580
+ cents: number;
6581
+ /** @description Part of `cents` held by an open refund and not spendable, in whole US cents, rounded down. */
6582
+ reserved_cents: number;
6583
+ };
6644
6584
  auto_topup: {
6645
6585
  enabled: boolean;
6646
- threshold_bytes: number | null;
6647
- amount_bytes: number | null;
6586
+ threshold_cents: number | null;
6587
+ amount_cents: number | null;
6648
6588
  monthly_cap_cents: number | null;
6649
6589
  monthly_spend_cents: number;
6650
6590
  };
@@ -6664,13 +6604,10 @@ export interface operations {
6664
6604
  content: {
6665
6605
  "application/json": {
6666
6606
  enabled: boolean;
6667
- /** @description Min 1 MB (1,000,000 bytes). Required when enabled. */
6668
- threshold_bytes?: number;
6669
- /**
6670
- * @description Allowed tiers — 5, 25, 50, 75, 100 GB (1 GB = 1,000,000,000 bytes). Required when enabled.
6671
- * @enum {integer}
6672
- */
6673
- amount_bytes?: 5000000000 | 25000000000 | 50000000000 | 75000000000 | 100000000000;
6607
+ /** @description Top up when the remaining value (plan allowance plus USD balance, priced at the plan's top-up rate) drops below this many US cents. Min $1. Required when enabled. */
6608
+ threshold_cents?: number;
6609
+ /** @description US cents added to the USD balance on each auto top-up, $5-$1000. Required when enabled. */
6610
+ amount_cents?: number;
6674
6611
  /** @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
6612
  monthly_cap_cents?: number | null;
6676
6613
  };
@@ -6685,8 +6622,8 @@ export interface operations {
6685
6622
  content: {
6686
6623
  "application/json": {
6687
6624
  enabled: boolean;
6688
- threshold_bytes: number | null;
6689
- amount_bytes: number | null;
6625
+ threshold_cents: number | null;
6626
+ amount_cents: number | null;
6690
6627
  monthly_cap_cents: number | null;
6691
6628
  };
6692
6629
  };
@@ -22,7 +22,7 @@ import type { ScrapeId, BulkId } from '../types.js';
22
22
  * so a receipt can arrive without your ever asking for one.
23
23
  * 3. Otherwise the fast HTTP path returns the 200 content envelope, typically
24
24
  * in under a second. A fetch that fails outright is a `failed` envelope on
25
- * that same 200, with `id: null`, because it ends before any job exists.
25
+ * that same 200; its `id` names the failed job, which `scrape.get(id)` returns.
26
26
  *
27
27
  * So a 202 is never a surprise: you either asked for it, or the hold expired.
28
28
  */
@@ -85,6 +85,8 @@ export interface ScrapeOpts {
85
85
  token_budget?: number;
86
86
  /** Tokenizer encoding hint for `token_budget`. `cl100k_base` (default) matches GPT-4/4o; `o200k_base` matches GPT-4o-mini / o-series. */
87
87
  token_encoding?: TokenEncoding;
88
+ /** Attempts to clear a Cloudflare challenge; success is not guaranteed. Billed as a normal browser render. */
89
+ solve_challenge?: boolean;
88
90
  /** When true, emulate a mobile device (mobile UA + viewport). Default false (desktop). Part of the cache key, so mobile and desktop responses cache independently. */
89
91
  mobile?: boolean;
90
92
  /** When true (default), base64-encoded `data:` image sources are stripped before markdown conversion. Set false to preserve them. Does not affect `raw`. */
package/dist/version.d.ts CHANGED
@@ -5,4 +5,4 @@
5
5
  * outbound request carries — see the emit site in `client.ts`. The header name is spelled
6
6
  * only there, so issue #2905's pre-merge gate 1 counts exactly one occurrence in `src/`.
7
7
  */
8
- export declare const SDK_VERSION = "0.10.0";
8
+ export declare const SDK_VERSION = "0.11.0";
package/dist/version.js CHANGED
@@ -9,4 +9,4 @@
9
9
  * outbound request carries — see the emit site in `client.ts`. The header name is spelled
10
10
  * only there, so issue #2905's pre-merge gate 1 counts exactly one occurrence in `src/`.
11
11
  */
12
- export const SDK_VERSION = '0.10.0';
12
+ export const SDK_VERSION = '0.11.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hunt-labs/bytekit-sdk",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Official TypeScript SDK for the ByteKit API",
5
5
  "license": "MIT",
6
6
  "type": "module",