Quickstart

Make your first ByteKit API call in under 5 minutes — no SDK required.

For AI agents: https://bytekit.com/llms.txt — every docs page is available as markdown by appending .md

Nothing to install. You only need curl and an API key.

Get an API key

Sign up at app.bytekit.com and create an API key from the dashboard. Keys are prefixed sk_live_.

See Authentication for details on key formats and management.

What you can try without paying

A new pay-as-you-go account receives a one-time starter grant of 100 MB of bandwidth and 100 credits. It is issued once per account, is not a purchase, and does not expire, so you can run the requests below without buying anything first. Real requests draw it down. See Balance and exhausted quota for how the grant is spent and what happens when a balance reaches zero.

Make your first scrape

Set your API key and run this — no file to save, no chmod:

curl -X POST https://api.bytekit.com/v1/scrape \
  -H "Authorization: Bearer $BYTEKIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com"}'

A successful response looks like this — every envelope field is snake_case:

{
  "schema_version": 1,
  "status": "success",
  "id": "sc_84c14b1058184045b97ae360ad74888b",
  "url": "https://example.com",
  "final_url": "https://example.com",
  "content_type": "text/html",
  "content_length": 318,
  "status_code": 200,
  "retrieved_at": "2026-08-27T12:16:01.872Z",
  "formats": {
    "raw": "<!doctype html><html lang=\"en\"><head><title>Example Domain</title>…</html>\n"
  },
  "metadata": {
    "title": "Example Domain",
    "description": null,
    "language": "en",
    "canonicalUrl": null,
    "ogTitle": null,
    "ogDescription": null,
    "ogImage": null,
    "ogUrl": null,
    "ogSiteName": null,
    "robots": null,
    "byline": null,
    "publishedAt": null
  },
  "cache": "miss",
  "billing": {
    "raw_bytes": 318,
    "factors": [{ "name": "endpoint", "value": 1, "reason": "scrape" }],
    "multiplier": 1,
    "billed_bytes": 318
  }
}

content_length is the compressed wire size in bytes (used for bandwidth billing), and billing breaks down what the request actually cost. cache is "miss" or "hit", and a hit adds a cache_age_s field. The id field uses the sc_ prefix — you can poll GET /v1/scrape/{id} if the scrape was queued asynchronously. A page that only a hosted browser could retrieve bills that browser's full measured transfer instead of one response.

The keys inside metadata stay camelCase (canonicalUrl, ogTitle, …): they are the page's own metadata, not envelope fields.

Ask for markdown

The default format is raw — that is why the response above carries no formats.markdown. Request markdown explicitly:

curl -X POST https://api.bytekit.com/v1/scrape \
  -H "Authorization: Bearer $BYTEKIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com","formats":["markdown"]}'

Markdown output is billed at 1.5× the request's upstream wire bytes — the endpoint factor in the billing node below is the rate your balance is charged, not a display weighting. See Bandwidth billing for how the factors compose.

The response's formats object is keyed by what you asked for:

{
  "schema_version": 1,
  "status": "success",
  "id": "sc_f659fa67dfb244159767132c2aa50917",
  "url": "https://example.com",
  "final_url": "https://example.com",
  "content_type": "text/html",
  "content_length": 318,
  "status_code": 200,
  "retrieved_at": "2026-08-27T12:16:11.337Z",
  "formats": {
    "markdown": "---\ntitle: \"Example Domain\"\nurl: \"https://example.com\"\ncaptured_at: \"2026-08-27T12:16:11.416Z\"\n---\nThis domain is for use in documentation examples without needing permission. Avoid use in operations.\n\n[Learn more](https://iana.org/domains/example)"
  },
  "metadata": {
    "title": "Example Domain",
    "description": null,
    "language": "en",
    "canonicalUrl": null,
    "ogTitle": null,
    "ogDescription": null,
    "ogImage": null,
    "ogUrl": null,
    "ogSiteName": null,
    "robots": null,
    "byline": null,
    "publishedAt": null
  },
  "cache": "hit",
  "cache_age_s": 8,
  "billing": {
    "raw_bytes": 318,
    "factors": [
      { "name": "endpoint", "value": 1.5, "reason": "scrape_md" },
      { "name": "cache_hit", "value": 0.5, "reason": "hit, age 8s" }
    ],
    "multiplier": 0.75,
    "billed_bytes": 239
  }
}

See Scraping for the other formats (markdown, links, images).

Prefer an SDK?

Skip the raw HTTP and use an official client:

Install @hunt-labs/bytekit-sdk (npm) / bytekit-sdk (PyPI). The npm package named bytekit is not ours.

Next steps

  • Authentication — key formats, Bearer header, self-serve key management
  • Scraping — formats, options, latency, and async polling
  • Errors — error shape, common codes, retry guidance
  • Rate Limits — usage counting, concurrency slots, rate limit headers
  • Monitors — page-change detection (screenshot or scrape) with webhook notifications
  • API Reference — full endpoint documentation