For developers / Application APIs

Explorer API

The archive the node deliberately is not. It holds the whole history, it is the only surface on this chain with call traces, and it is read-only in the strongest sense - every POST is a 405.

Why this exists

The node keeps a short window of history - roughly two minutes of blocks - and a query outside it answers null rather than an error. That is a deliberate trade: it serves the present quickly and hands the past to something built for it. This service is that something. The sequencer copies every log into Postgres as it goes, and this API reads that index.

So two questions are answered here and nowhere else:

  • Anything older than the node's window. A transaction from this morning, a block from last week, a token's whole transfer history.
  • Call traces. The node exposes no debug namespace at all, so GET /tx/{hash} is the only place on this chain to see the internal calls of a transaction.
It is an index, not a second node

Some fields on some routes are read live from the node as the request is served - a balance, a name-service record, a contract probe, the mini-blocks of a block the index has not caught up to. When the node is unreachable those come back null or absent while the rest of the answer is served from the index, so a partial answer is normal and does not raise an error.

Base URL and CORS

EndpointValue
Publichttps://explorer.picklechain.xyz/api/also mounted at /api/ by the name-service and toolkit sites
A stack you runhttp://127.0.0.1:4010the service's own port; it is not published outside the container network in the shipped compose file
CORSan allowlistOPTIONS answers 204 with GET and OPTIONS allowed; an Origin not on the list is refused 403

Chain

Blocks, mini-blocks, transactions and the fee split.

Params
none
Returns
a flat object of counters

Chain-wide counters: block and transaction totals, wallets, gas used, the cadence figures the node reports, the mini-block head, index lag and the spool's own health.

Also at. GET /

Worth knowing. Recomputed once a second by a background thread and served from a cache for six tenths of a second, so two calls in the same instant give the same answer. It also carries a rate counter this reference does not quote: the site publishes no throughput figure, and the number is local anyway.

Params
none
Returns
{stats, charts, blocks, txs, topAccounts}

The explorer's front page in one call: the cached stats, 48 chart points, the 8 most recent blocks that carried transactions, 12 transactions and the 8 busiest accounts.

Worth knowing. Use this instead of five calls. Its parts are the other routes' defaults and nothing about it is configurable.

Params
limit (default 48, clamped to 200)
Returns
[{number, timestamp, txCount, gasUsed}]

A bare array, oldest first.

Worth knowing. It prefers blocks that carried transactions and falls back to all blocks only when fewer than four match, so the series is not evenly spaced in time and must not be read as one.

Params
limit, offset, active=1
Returns
[{number, hash, timestamp, gasUsed, txCount, miniCount}]

A bare array, newest first. `active=1` returns only blocks that carried transactions.

Worth knowing. No total is returned, so there is nothing to page against except asking until you get a short answer.

Params
limit, offset over the block's transactions
Returns
one block with its transactions and mini-blocks

The number is parsed permissively: decimal and 0x both work.

Worth knowing. `limit` defaults to 50 here rather than 25, and the mini-blocks fall back to a live read against the node when the index has none for the block. 404 when unknown.

Params
limit, offset
Returns
{total, minis: [...]}

Mini-blocks, newest first. One of the few routes that does return a total.

Worth knowing. Timestamps are `timestamp_us`: MICROSECONDS, not seconds, and a decimal number rather than a hex quantity.

Params
limit, offset over the transactions
Returns
one mini-block

By decimal number or by hash.

Worth knowing. When the index does not have it, the service asks the node - and the answer then ALSO carries `stateDiffHash`, `sequencerSig` and `receipts`, which the indexed answer does not. The shape depends on where it was found.

/txs

GET
Params
limit, offset
Returns
a bare array, newest first

Transaction summaries.

Worth knowing. No total.

Params
none
Returns
the full transaction

The richest object in the API: input data, the decoded method for known selectors, logs with labelled addresses, CALL TRACES, token transfers and NFT transfers.

Worth knowing. The traces are the reason this route exists. The node exposes no debug namespace at all, so there is nowhere else on this chain to get them. 404 when unknown.

Params
none
Returns
{deployed, router, split, burn, launches, arcadeSkims, deferred, claimed, pendingEthWei, ...}

Everything the fee split has done and everything still waiting, read from the log spool rather than over RPC.

Worth knowing. `{"deployed": false}` and NOTHING ELSE when the fee layer is not in the manifest - that is an ordinary state, not an error, because that layer is deployed by hand. The ether side and the token side are kept as separate figures and never summed.

Accounts

Who transacted, and everything known about one address.

Params
limit, offset
Returns
{total, accounts: [...]}

Accounts ordered by how much they have transacted.

Worth knowing. The ordering is by transaction count, not by balance.

Params
limit, offset over the transaction lists
Returns
the largest payload in the service

Balance, nonce, counts, whether it is a contract, its creator and what it created, token and NFT holdings with metadata, the name-service record, and recent transactions and transfers.

Worth knowing. `bytecode` is TRUNCATED to 400 hex characters with an ellipsis appended; `bytecodeSize` is the real length. The whole answer is cached for a few seconds under a key that includes the paging, so two different pages are two different cache entries.

Tokens, NFTs and names

Registry-merged metadata, and the one route that is not JSON.

Params
none
Returns
a list of at most 40 tokens

PKL pinned first, then by transfer count. Each entry merges a live probe of the contract with the operator's registry entry.

Worth knowing. Forty is a hard cap and there is no paging past it. An address that probes as an NFT is skipped even if the registry calls it a token.

Params
none
Returns
{nfts: [...]}

At most 40 collections, verified ones first, then by how many have been minted.

Worth knowing. The collection list is DISCOVERED from transfer logs rather than registered, so a collection nobody has traded is absent.

Params
limit, clamped to 48
Returns
the collection, its items and its 30 most recent transfers

Collection metadata merged from the chain and the registry.

Worth knowing. Items are fetched one at a time up to the clamp, and off-chain metadata is resolved by a BACKGROUND thread - so the first request for a cold collection returns items whose metadata is still missing, and a second request a moment later returns more. Held for fifteen seconds in a cache of its own.

Params
none
Returns
one item plus `collectionMeta`

One token of a collection.

Worth knowing. The token id must be all digits, or the path does not match this route at all and you get the 404 for an unknown route.

Params
none
Returns
{name, label, available, reserved, owner, resolved, expires, price, twitter, website, description}

A name-service lookup, read live from the registry contract.

Worth knowing. A trailing suffix is stripped, and the label must be 3 to 32 characters. A name outside that range, and any lookup at all when the name service is not configured, is a 404 - which is indistinguishable from a name that does not exist.

Params
none
Returns
raw image bytes

The only non-JSON, non-stream route. The content type is inferred from the stored file's extension.

Worth knowing. 404 as JSON when there is no logo, so a client must check the status before treating the body as an image.

Live, and the two non-GET verbs

The event stream, the preflight, and the 405.

Params
none
Returns
text/event-stream, one stats frame per update

Server-sent events carrying the same object /stats returns, pushed when it changes.

Worth knowing. Bounded to 32 concurrent streams - the 33rd gets 503 - and the server CLOSES every stream after five minutes. A client that does not reconnect simply stops receiving, with no error.

any

OPTIONS
Params
none
Returns
204

The preflight. Allowed methods are GET and OPTIONS, allowed header is Content-Type.

Worth knowing. 403 when an Origin is present and not on the allowlist, rather than a 204 without the allow header.

any

POST
Params
none
Returns
405

This API is read-only and answers 405 to every POST, in JSON and with the CORS headers.

Worth knowing. It had one write route: a token-metadata edit signed by the contract's owner. It is gone, along with the form that called it, because an explorer that takes visitor-supplied identity for an asset is an impersonation surface.

Limits, paging and caches

LimitValue
Request rate300 per minute per client addressthen 429; the window is wall-clock and resets on the minute
Client identitythe rightmost trusted X-Forwarded-For entryindexed from the right by the number of trusted proxy hops, because the leftmost entry is whatever the client wrote
Request body600,000 bytesthere is nothing to POST, but the cap exists
List paginglimit <= 100, offset >= 0a non-numeric limit silently becomes the default rather than erroring
Live streams32 concurrent, 300 seconds each503 above the first, silent close at the second
Answer cacheabout 3 secondson /address, /tokens, /nfts and the NFT routes; the stats cache is shorter

The rate limit is per client address, and it is shared with the explorer's own page

Three hundred requests a minute is generous for a person and thin for a backfill. The window is wall-clock: it resets on the minute rather than sliding, so a burst at the turn of a minute can spend two windows' worth in two seconds and then answer 429 for the rest of the second one. There is no retry-after header on this service - back off yourself.

The identity behind the count is the forwarded client address, read from the right-hand end of the chain because the leftmost entry is whatever the caller wrote. Behind a proxy that does not append, every caller collapses into one bucket and the whole internet shares one budget.

Paging is limit and offset, clamped to a hundred. A non-numeric limit becomes the default rather than an error, and a negative one becomes one - so a malformed request gets a plausible answer rather than a complaint. Most list routes return no total; /minis and /accounts are the exceptions.

Answers are cached for a few seconds

/address, /tokens, /nfts and the NFT routes are held in a short-lived cache keyed by path and paging, and /stats is recomputed by a background thread and served from a cache shorter still. Two identical requests in the same instant give identical answers, which is fine for a page and wrong for a confirmation loop. Poll the node for a receipt, not this.

Freshness and lag

/stats carries the numbers that say how current the index is: indexedBlock against latestBlock, indexLag as the difference, and derivedLag for the materialised views - token balances and NFT ownership are built by separate workers and can trail the transactions they come from.

bash
# Is the archive current? Compare the two, do not trust either alone.
curl -s "$EXPLORER_API/stats" | jq '{latestBlock, indexedBlock, indexLag, derivedLag}'

# One transaction, whole, traces included. This is the route with no substitute.
curl -s "$EXPLORER_API/tx/$HASH" | jq '{success, decoded, traces: (.traces|length), tokenTransfers}'

# Page an address's history by offset - and see the note below before relying on it.
curl -s "$EXPLORER_API/address/$ADDR?limit=100&offset=0" | jq '.transactions | length'

Offset paging shifts under a growing list

Every list here is newest-first, and new rows arrive at the head. Page two, fetched a moment after page one, therefore overlaps it - and rows can be skipped entirely while you walk. For a backfill that must be complete, page by block number and work downwards, or fetch a block at a time; offset is for a user interface, not for an importer.

One more asymmetry worth knowing before you key anything: this chain enumerates logIndex per transaction rather than per block, so the pair (blockNumber, logIndex) is not unique. Include the transaction hash in any key you build.