> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bloklake.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Core concepts

> Everything you need to know to use Bloklake well, on one page.

## Chains and base URLs

Each chain has its own base URL. Every route hangs off it:

```text theme={null}
https://api.bloklake.com/v1/chains/eth/query
https://api.bloklake.com/v1/chains/rh/status
```

Each chain also has its own hostname (`https://eth.api.bloklake.com/query`); the two forms are
equivalent. `https://api.bloklake.com/query` on its own does not pick a chain and returns `404`.
**One API key works on every chain.**

## Row types

Bloklake stores three kinds of rows per chain:

| Row type | One row per | Ordered by | Filter on |
| - | - | - | - |
| `logs` | event log | `(block_number, log_index)` | `address`, `topic0`–`topic3` |
| `transactions` | transaction (with its receipt fields) | `(block_number, transaction_index)` | `from`, `to`, `sighash`, `status`, `type` |
| `blocks` | block header | `number` | the block range only |

Transaction rows include the receipt (`status`, `gasUsed`, `effectiveGasPrice`,
`contractAddress`, …), so you never need a separate receipts call.

## A query

A query is a JSON body sent with `POST`:

```json theme={null}
{
  "fromBlock": 19426000,
  "toBlock": 19426099,
  "logs": [{"address": ["0xa0b8…eb48"], "topic0": ["0xddf2…b3ef"]}],
  "fields": {"log": {"blockNumber": true, "topic1": true, "topic2": true, "data": true}}
}
```

* **Range**: `fromBlock`–`toBlock`, both inclusive. Leave `toBlock` out to read up to the head.
* **Filters**: `logs` and/or `transactions`, each a list of filter objects. Within one object
  every field must match (AND). A row matches if any object matches (OR).
* **Fields**: which columns to return, per row type. You get only what you select, which keeps
  responses (and your bill) small.

[Request body](https://docs.bloklake.com/querying/request-body.md) documents every key.

## Two response formats

| | `POST /query` | `POST /query/json` |
| - | - | - |
| Format | Apache Arrow IPC streams | One JSON object |
| Size | smaller | about 2–2.5× larger |
| Cost | billed on Arrow size | billed on JSON size |
| Page size | up to 100,000 objects / \~8 MB | up to 100,000 rows |
| Use for | everything real | trying things out, debugging, `curl` |

[Arrow vs JSON](https://docs.bloklake.com/responses/arrow-vs-json.md) explains when to use which.

## Responses are pages

One response covers **at most 50,000 blocks**, **about 8 MB of data** and **about
`maxObjects` objects** (default and maximum 100,000). It always ends on a block boundary: a
block's rows are never split across two responses.

Every response tells you where to continue: `next_block`. Keep requesting from `next_block`
until it passes the end of your range. This loop is the core of every Bloklake client; see
[Pagination](https://docs.bloklake.com/querying/pagination.md).

> [!WARNING]
>
> Never assume a response covers the whole range you asked for. Read `from_block`, `to_block`
> and `next_block` from the response.

## The head, finality and reorgs

`archive_height` is the newest block you can query. Blocks near the head can still be replaced
by a reorg; `finalized_block` is the newest block that can't. A response that ends above the
finalized block carries `to_block_hash` so you can detect a reorg when you re-read the range.
See [Finality and reorgs](https://docs.bloklake.com/querying/finality-and-reorgs.md).

## Billing in one paragraph

You pay for the **data Bloklake sends you**: the bytes of the rows in each response (not
headers or metadata), with a minimum of 10 KB per request. Errors and refused requests are
free. Selecting fewer fields and using Arrow instead of JSON both make the same rows cheaper.
See [How billing works](https://docs.bloklake.com/billing/how-billing-works.md).

## Rate limits in one paragraph

Each key has a requests-per-second limit (1 on pay-as-you-go, 10 on Standard) shared across
all chains, and a limit on how many of its requests can be open at once. Over the limit you get
`429` with `Retry-After`. See [Rate limits](https://docs.bloklake.com/production/rate-limits.md).

## Sets and prepared queries

If your filter has thousands of addresses, upload them once as a **set** and refer to it by id.
If you run the same filter over and over with different ranges, reuse its **prepared query id**
instead of resending the body. Both make requests smaller and faster. See [Sets](https://docs.bloklake.com/querying/sets.md)
and [Prepared queries](https://docs.bloklake.com/querying/prepared-queries.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.