# Fetch Bulk

Functions for interacting with the `fetch_bulk` API resource. Each operation ships in four forms — `sync` / `sync_detailed` and their `async` counterparts.

## Create Fetch Bulk

Bulk fetch URLs

Enqueues multiple URLs for HTTP fetching. Results delivered via webhook.
Does not support options that require page rendering (wait_for_selector, etc.).
Completion deliveries use `X-ByteKit-Event: bulk.completed` and the
`BulkCompletedWebhook` contract: at most 500 complete items and 1 MiB,
followed by cursor recovery through `GET /v1/fetch/bulk/\{id\}` whenever
`recovery_required` is true.

**Limits:** request bodies are guarded in a two-tier shape. A streamed body
with no `Content-Length` header is capped at 2 MB before your API key
is checked; a body that declares `Content-Length` is instead bounded
there by a 20 MB fail-safe (not the real limit — see below), since
that branch reads nothing until your key is verified. Once your key
is verified, a second check re-gates the body against your account's
own `max_bulk_size` (at this endpoint's per-item override budget),
which reaches 16.8 MB for the largest documented account. A
standard-plan account's effective ceiling is 2 MB; either tier's
overrun returns a `400` with error code `request_too_large`.

**Parameters**

- `body (CreateFetchBulkBody)`
- `urls` — `list[CreateFetchBulkBodyUrlsItemType1 | str]`
- `webhook_url` — `str` — Webhook endpoint URL (HTTPS only; http:// rejected with 400 invalid_url, reason scheme_unsupported)
- `defaults` — `CreateFetchBulkBodyDefaults | Unset`
- `webhook_secret` — `str | Unset` — HMAC secret used to sign webhook deliveries. Each delivery carries `X-Webhook- Timestamp` and `X-Webhook-Signature` (`sha256=` + the hex HMAC-SHA256 of `timestamp.body`). See https://bytekit.com/docs/guides/webhooks for verification code.
- `metadata` — `Metadata | Unset` — Arbitrary key-value metadata. Max 4096 bytes when JSON-serialized.

**Call styles**

```python
sync_detailed(client=client, body=body) -> Response[CreateFetchBulkResponse202 | CreateFetchBulkResponse403 | Error]
sync(client=client, body=body) -> CreateFetchBulkResponse202 | CreateFetchBulkResponse403 | Error | None
await asyncio_detailed(client=client, body=body) -> Response[CreateFetchBulkResponse202 | CreateFetchBulkResponse403 | Error]
await asyncio(client=client, body=body) -> CreateFetchBulkResponse202 | CreateFetchBulkResponse403 | Error | None
```

## Get Fetch Bulk

Get fetch bulk job status

Returns the job envelope plus its per-URL items.

**Downloading item content.** Each completed item's `content_url` is a
**pre-signed** URL, minted fresh on every read of this endpoint and valid
for **600 seconds (10 minutes)** — the same signing lifetime as the
`image_url` returned by `GET /v1/bulk/\{id\}/screenshots`. The underlying
objects are private, so an unsigned URL returns `401`: download the
content inside that window, or re-poll this endpoint for a fresh
signature. Items that are not `completed`, and completed items with no
stored object, or completed items whose object cannot be signed, carry
`null`; the latter report `artifact_unavailable`. The private unsigned
storage URL is never returned.

**Cancelled by the platform.** When the account can no longer spend (its bandwidth
balance is exhausted, or the account is deleted) while items are still pending, ByteKit
cancels the job itself. It then reads `status: cancelled` even though you never called
`DELETE /v1/bulk/\{id\}`, and the cancellation sends no webhook.

**Job ids from other create routes.** The job is looked up by account only, so the id
of a job created by `POST /v1/scrape/bulk` or `POST /v1/bulk` is found here too, not a
`404`, with the job envelope and `items: []`: only items fetched through
`POST /v1/fetch/bulk` are listed. An id from another account answers `404`.

**Parameters**

- `id (str)`
- `cursor (str | Unset)`
- `limit (int | Unset)`
- `status (GetFetchBulkStatus | Unset)`

**Call styles**

```python
sync_detailed(id=id, client=client, cursor=cursor, limit=limit, status=status) -> Response[Error | GetFetchBulkResponse200 | GetFetchBulkResponse202]
sync(id=id, client=client, cursor=cursor, limit=limit, status=status) -> Error | GetFetchBulkResponse200 | GetFetchBulkResponse202 | None
await asyncio_detailed(id=id, client=client, cursor=cursor, limit=limit, status=status) -> Response[Error | GetFetchBulkResponse200 | GetFetchBulkResponse202]
await asyncio(id=id, client=client, cursor=cursor, limit=limit, status=status) -> Error | GetFetchBulkResponse200 | GetFetchBulkResponse202 | None
```