API Conventions
Behavior shared by all indexer API endpoints.
Pagination
List endpoints support two pagination styles: simple offset-based paging and opaque keyset cursors. Both validate items the same way.
items validation
| Parameter | Type | Default | Description |
|---|---|---|---|
items | integer | 10 | Page size, capped at 100 |
items must be at least 1 (items=0 → 400 "Invalid number of items") and at most 100; non-numeric values are rejected as well. This applies to both pagination styles.
Offset pagination
For shallow listing ("the first few results"), pass offset:
| Parameter | Type | Default | Description |
|---|---|---|---|
offset | integer | 0 | Number of items to skip |
curl "https://api-server.mintlayer.org/api/v2/transaction?offset=0&items=20"
Deep offsets re-read every preceding row on each request, so they get slower the deeper you page. For long walks, use keyset pagination instead.
The transaction list endpoint additionally accepts offset_mode:
offset_mode | Behavior |
|---|---|
legacy (default) | Page over the index in storage order; newest pages can shift as new blocks arrive |
absolute | Page over a stable, global transaction index (global index assigned at insert time) |
Use absolute when you need stable pagination (e.g. syncing all transactions); use the default for "recent activity" views.
Keyset pagination (cursors)
Deeper listings (pools, transactions, address balance holders, and the order book) accept an opaque cursor query parameter instead of relying on deep offsets:
curl "https://api-server.mintlayer.org/api/v2/pool?cursor=<next_cursor>&items=100"
- The cursor is an opaque string (base64-encoded JSON, at most 1 KiB and 16 keys). Treat it as a black box: never construct, decode, modify, or store one beyond the life of the walk, pass back exactly what the server returned. An empty value (
cursor=) starts the listing from the beginning. - When a
cursorparameter is supplied, the response is an envelope instead of a plain array (the holders and order book endpoints always return the envelope):
{
"items": ["..."],
"next_cursor": "eyJ0YWciOiJwb29scyIsImtleXMiOlsiMTAyMzAwIl0sImlkIjoibXBvb2wx..."
}
- Pass
next_cursorback ascursorto fetch the following page. Anullnext_cursormeans the listing is exhausted. (For the order book,nullcan also mean the walk was cut short by the server-side scan cap; see Orders.) - Ordering is stable, newest first. Ties are broken by descending byte-order ID, so equal-ranked entries keep a fixed relative order across pages. Transactions additionally order by ascending transaction index within a block, so consecutive pages reconstruct each block's transaction order.
- If both
cursorandoffsetare given, the cursor takes precedence. - Pages are guaranteed stable only once the scanner has fully caught up with the chain tip. While it is catching up (e.g. after a reorg), a concurrent walk may skip or repeat an entry.
Offset pagination remains the simple alternative for shallow listing; cursors are the right tool whenever a full listing needs to be walked.
Amounts
All amounts are returned as an object with two representations:
{"atoms": "148200000000", "decimal": "1.482"}
atomsis the smallest unit (1 ML = 10^11 atoms), as a decimal string.decimalis the human-readable amount, as a string.
Both are strings to avoid losing precision in JSON number parsing. Always do arithmetic on atoms.
Identifiers and encodings
| Kind | Format | Example |
|---|---|---|
| Block / transaction IDs | 64-character lowercase hex | 7c337ff1a81fea9d2b394d251b7f115abbef53535cfc4ec32b994a63d0f17b77 |
| Addresses | Bech32, network-prefixed | mtc1q8n9u3g3aw4h40gsagxn7yw0jatdfe9xsuftnvur |
| Token IDs | Bech32 (mmltk1... on mainnet) | mmltk1q43gmfrsau2lnev65d56a4w02a70s7j6ccvc8jlx6twy2e75fa2q45h2wd |
| Pool IDs | Bech32 (mpool1...) | mpool18qt05uxz52fme32jxx5r64h5tlkxk9m6kw6lq84jezxpqr853x8sdat9x4 |
| Delegation IDs | Bech32 (mdelg1...) | mdelg1zf3l695cfaa0vldfc3fv4q65f6n30w832jkptwgfry3du63hx9gq42t3f0 |
| Order IDs | Bech32 (mordr1...) | mordr1u8kjudmqwpx0fv9nc3ltgcyfsrllepva9hh2zz9z3gwd6g0yql9sjkfr3l |
Mainnet addresses and IDs start with m; testnet uses different HRP prefixes (tmtr...-style). An address format that is valid for the wrong network is rejected with a client error.
Timestamps
Unix timestamps in seconds. Range-filtered endpoints (e.g. pool block stats) take from and to query parameters.
Errors
- Unknown routes return a plain-text
404 page not found. - Malformed parameters or malformed IDs return HTTP 400 with a JSON body:
{"error": "..."}. - Resources that exist but are not found (e.g. an unknown transaction ID) return HTTP 404 with a JSON body describing the missing object.
Note that some list endpoints return an empty array [] rather than an error when no data matches.
Data freshness
The indexer follows the chain tip; data appears after the scanner processes a block. Under normal operation this lag is a few seconds.