# Bandwidth billing

How ByteKit measures billed bandwidth for capture and sitemap endpoints.

ByteKit bills most capture endpoints from bytes transferred over the upstream wire, not from the size of the final JSON, Markdown, or image artifact. Sitemap jobs use the generated results artifact instead, as described below.

## Upstream wire-byte endpoints

For scrape, fetch, and monitor requests, the amount taken from your balance is calculated once, at settlement, and rounded once:

```
balance deduction = round(upstream wire bytes × endpoint factor × cache factor × clean-Markdown factor)
```

A page that only a hosted browser could retrieve has no single upstream response, so its upstream wire bytes are the browser's full measured transfer: every response the page loaded plus the requests the browser sent.

A cache hit contributes a **0.5×** factor. Successful clean-Markdown processing contributes a separate **3×** factor. The endpoint factor is listed below. All three compose; they are not alternative rates.

### Endpoint factors

Each endpoint carries a factor reflecting the work it performs:

| Endpoint                    | Factor |
| --------------------------- | -----: |
| Scrape                      |     1× |
| Scrape with Markdown output |   1.5× |
| Fetch                       |     1× |
| Monitor run                 |     1× |

Requesting Markdown output raises a scrape from 1× to 1.5×, so a Markdown scrape deducts one and a half times its upstream wire bytes. `/v1/fetch` takes no `format` and has no Markdown output; request Markdown from `/v1/scrape`.

This factor is part of what you are charged. `GET /v1/usage/by-endpoint`, the per-endpoint table under **Dashboard → Usage**, the `billing` object on each response and the `X-Billable-Bytes` header all report the same amount your balance lost — there is no separate reporting weight to reconcile.

Screenshot captures bill on a different basis, described under [Other capture artifacts](#other-capture-artifacts).

### Legacy usage buckets

The legacy buckets below are not endpoints you can call. They stay in the list of values `GET /v1/usage/by-endpoint` can report, with these factors:

| Usage bucket                        | Factor |
| ----------------------------------- | -----: |
| Crawl (legacy)                      |   1.5× |
| Crawl links (legacy)                |     1× |
| Fetch with Markdown output (legacy) |   1.5× |

ByteKit has no crawl endpoint. `/v1/fetch` has no Markdown output, so the Markdown-fetch bucket appears only in historical usage reports. The deactivated recordings endpoint likewise leaves a legacy bucket that appears only in historical usage reports; its basis is under [Other capture artifacts](#other-capture-artifacts).

## Charges that survive a failure

A request that fails with a terminal error has its pre-incremented amount rolled back, as the [Usage counting](https://bytekit.com/docs/guides/rate-limits#usage-counting) section describes. Two charges survive a failure. A `/v1/fetch` request answered from the cache with a non-2xx upstream status is billed at the cache-hit rate, and a failed schema extraction refunds the credits it pre-charged but keeps the source page's bandwidth. That cached non-2xx hit returns the `upstream_error` envelope — the same JSON a cache miss with the same upstream status returns — not the cached body, which stays the billing basis even though it is not served.

## Bulk

A bulk job has **no endpoint factor of its own**. Each item settles independently, on exactly the basis the same request would use on its own: a scrape item as a scrape and a fetch item as a fetch, at that endpoint's factor from the table above, and a screenshot item — the type `/v1/bulk` assumes when you do not name one — on the separate capture basis under [Other capture artifacts](#other-capture-artifacts), which the table above does not cover.

Whatever factors an item would carry alone, it carries in bulk: a cache hit still contributes **0.5×**, and successful clean-Markdown processing still contributes **3×** on the `/v1/scrape/bulk` items that can request it. A job's billed total is the sum of its items, with no per-job fee, no bulk surcharge and no bulk discount.

So a bulk job of Markdown scrapes bills at **1.5× per item, not 1×**: the Markdown surcharge is an endpoint factor, and bulk does not suppress it. Sending URLs in bulk saves you round trips, not bytes — the charge for each item is the same as it would be on its own request.

## Sitemap

Sitemap billing uses the byte length of the **gzip-compressed generated results CSV**. ByteKit builds the results CSV for the job, compresses it, and bills that compressed length — the same figure your sitemap usage reports.

Discovery fetch bytes are not accumulated into the sitemap charge. The charged byte count is the compressed results artifact, not the upstream bytes transferred while discovering URLs.

A sitemap request that reuses an earlier job's results (`cache: hit` on the `202` response) carries the **0.5×** cache-hit factor on that same compressed size.

## Other capture artifacts

Screenshots use a separate capture basis: 1.5× the wire bytes of the initial page fetch, rounded to whole bytes. The extra 0.5× covers rendering the page. If that initial fetch has no positive wire-byte measurement, the capture contributes zero billable bytes.

Recordings were billed on that same basis, except older recordings in historical usage reports, which were billed on the size of the recording file. The `/v1/recordings` endpoint is deactivated, so the `recordings` bucket can appear only in historical usage reports.

Your current allowance, purchased bandwidth, rollover bandwidth, and remaining balance are shown under **Dashboard → Settings → Billing**.