Skip to main content
The Explorer GraphQL API answers three common questions: what happened to a message, how many messages match a filter, and which domains are indexed. Use it to build delivery trackers, message history, and activity dashboards. Add the WebSocket API when you need live updates. Send GraphQL queries to:
The public endpoint is read-only and requires no API key. Send an HTTP POST with Content-Type: application/json and a JSON body containing query and, optionally, variables. GraphQL mutations, GraphQL subscriptions, and public schema introspection are not supported.

Choose your query

message_view also includes the message body, sender and recipient, block details, transaction gas fields, and gas-payment totals. You only receive the fields you select. These APIs expose the Explorer’s indexed data, not every transaction or contract on every Hyperlane-connected chain. Coverage and freshness depend on the scraper. A domain record identifies a known chain; it does not guarantee current indexing health. Configuring a custom chain in the Explorer UI does not add that chain to the public API’s indexed history. A message lookup joins its origin dispatch with the indexed destination delivery. is_delivered: true means the scraper has observed a matching delivery at the requested confirmation level. false or an empty result can also reflect indexing lag or missing coverage; neither proves that an on-chain transaction failed. These queries read the index rather than making a fresh destination RPC call.

Run any example

Click Run query on any example below. The request runs against the public API, and its JSON response appears directly beneath that example. Edit the query or its variables and run it again; Reset restores the original example. Requests only run when you click the button. Message lookups include a sample ID so you can try them immediately. Replace the id variable with your own message ID to check its delivery. Use the field reference to choose additional fields.
Check the response’s errors array, even when the HTTP status is 200. A request can return partial data alongside errors.

Messages: message_view

Look up a message and its delivery

To use a message ID copied from the Explorer, replace its leading 0x with \x. Keep all 64 hexadecimal characters unchanged; no hashing or other conversion is needed.In the Variables JSON editor above, write two backslashes (\\x) so JSON decodes them into one literal backslash:
In JavaScript, convert the ID and let JSON.stringify handle JSON escaping:
The bytea value starts with one backslash and x; the second backslash only escapes it in JSON or JavaScript source.
Destination transaction details and delivery timestamps can be null before delivery or while enrichment is incomplete. sender and recipient are the Hyperlane application addresses; origin_tx_sender and destination_tx_sender identify transaction senders, which can be different accounts.

Choose your confirmation count

Set confirmations to your own non-negative number of confirmations, such as 0, 2, or 5 (maximum 1,000). The same number is checked independently against each chain’s own head: origin dispatches wait for origin-chain confirmations, and destination deliveries wait for destination-chain confirmations. For example, with confirmations: 5, a delivery in destination block 100 becomes eligible once the observed destination head reaches 105 and the scraper has indexed the delivery. Origin-chain progress does not satisfy the destination’s threshold. The message can appear earlier with is_delivered: false if its dispatch is eligible but its delivery is not. A GraphQL request returns the eligible state at query time; it does not stay open waiting for confirmations. Query again later or use the WebSocket API for updates when the threshold is reached. Omitting confirmations, or passing null, returns canonical scraper data using the configured default. Set confirmations: 0 to include the most recently indexed dispatches and deliveries without waiting for that canonical boundary: Change confirmations: 0 in this example to confirmations: 5 to request five confirmations. For confirmations: N, eligible data is bounded by min(indexed height, observed head height - N) on each chain. Heights use the chain’s native units, such as Sealevel slots.
Zero confirmations means observed delivery, not final delivery. A reorganization can remove it. It does not accelerate relaying or remove RPC and indexing delays. Chains without near-head indexing state retain canonical behavior even when you request zero confirmations.
is_provisional indicates that the returned snapshot row differs from canonical scraper state. It is not a confirmation count or a separate finality flag for the destination. To check canonical delivery, query the same message again with confirmations omitted. Use the WebSocket API for push updates. For polling, use a bounded interval and back off after errors; avoid a tight request loop.

Where to find default confirmations

Look in chains/<chain-name>/metadata.yaml in the Hyperlane Registry, for example Ethereum or Base:
  • blocks.reorgPeriod configures the scraper’s canonical confirmation boundary. It can be a numeric delay or a chain-specific finality selector, such as a block tag.
  • blocks.confirmations is a separate transaction-confirmation setting; it is not the Explorer API’s default confirmation delay.
Registry metadata is the configuration source, not a live report of the deployed scraper. Agent configuration can override it; see the agent configuration builder and scraper confirmation behavior. An explicit API confirmations value requests your chosen delay on chains that support custom confirmations.

Search and filter messages

Fetch recent indexed messages from Ethereum to Base. Replace these domain IDs with your route’s domains: id orders database records, not a globally ordered timeline across chains. To sort by dispatch time, use order_by: [{send_occurred_at: desc}, {id: desc}] for a bounded search. Find messages associated with either an origin or destination transaction: Pass hash in the same bytea format as the message ID. Query the two transaction fields separately, as above, to avoid a broad OR scan across origin and destination joins. Merge data.dispatched and data.delivered by msg_id if you need one list. You can also filter sender, recipient, origin_tx_sender, or destination_tx_sender by address. Filters support _eq, _neq, _gt, _gte, _lt, _lte, _in, _nin, and _is_null. Combine conditions with _and, _or, and _not. Multiple fields in a where object are combined with AND. For example, add is_delivered: {_eq: false} for indexed undelivered messages, or a send_occurred_at range to bound a search.

Paginate canonical history

Fetch the first page with order_by: {id: desc} and an explicit limit. For the next page, use the last row’s id as $before: Pass the cursor as a decimal string, for example {"before":"165103325"}, and retain your original where filter on each page. Continue until a page is empty. For ascending traversal, use id: asc and ordering: ASC. Cursors support only the id column and must match the sort direction. They are for canonical history: do not combine them with confirmations. Provisional and canonical IDs can come from different sequences; merge live records by msg_id, not database id. For a historical export, use bounded pages and retain a high-water mark. Delivery status on previously fetched rows can change later, so a one-time traversal is not an ongoing delivery monitor. Reconcile outstanding messages or consume WebSocket updates separately.

Counts: message_view_aggregate

Replace the example time range as needed. Aggregates use canonical data and do not accept confirmations. Prefer filters on chain, message, or time over repeated full-history counts.

Chains: domain

Results are under data.domain. id is the Hyperlane domain ID used in message filters and WebSocket subscriptions; it is not necessarily the chain’s native chain_id. For example, Ethereum uses domain 1 and Base uses 8453. Remove the is_test_net filter to include testnets. If the result fills a page, add id: {_gt: LAST_ID} to where and continue with the same ascending sort until a page is empty. For a known domain, domain_by_pk(id: 1) { id name chain_id } performs a single-record lookup. The full schema also exposes raw dispatch records for specialized indexing use cases. Start with message_view for application integrations: it combines dispatch and delivery data in one result.

Data formats

  • Hashes, addresses, and bodies: bytea values use a literal \x prefix followed by hexadecimal bytes. In JSON or JavaScript string literals, escape the backslash as "\\x...". Convert a 0x-prefixed hex message ID by replacing the prefix. For non-hex chain addresses or transaction signatures, decode the chain-native representation into bytes first. Address filters must match the stored byte length; EVM addresses are commonly stored as 20 bytes.
  • Large integers and amounts: bigint and numeric values are returned as strings. Preserve their precision with BigInt for integers or a decimal library for amounts. Gas-payment totals are raw units, not USD values or decoded Warp Route transfer amounts.
  • Times: timestamps represent UTC and can be returned without a timezone suffix, for example 2026-11-04 08:55:51. Parse them explicitly as UTC. delivery_latency is a PostgreSQL interval string, not a numeric seconds field.
  • Missing fields: transaction enrichment and delivery fields can be null. A provisional delivery may have a transaction hash and block height before every transaction field is available.

Limits and troubleshooting

  • Row queries return at most 500 rows per query field; use smaller explicit pages. Offsets are capped at 5,000. _in / _nin lists accept at most 200 values.
  • Custom GraphQL confirmations accept 0–1,000. These snapshots reject cursors and non-zero offsets, and cap affected events at 10,000. If a snapshot exceeds the cap, narrow by msg_id using _eq or _in, or query canonical history.
  • Submit one GraphQL operation per request. Narrow queries and select only the fields you need. Back off on rate limits, timeouts, and transient server errors.
  • An error on a custom snapshot can return null for that field alongside successful results for other query fields. Handle errors before treating a result as empty.
  • An empty result can mean an incorrect byte encoding, an unindexed chain, indexing lag, or a dispatch that has not reached canonical visibility. Check the message ID, domains, and requested confirmation level.
For the complete current field list and server limits, see the GraphQL schema, query limits, and snapshot contract.
Older integrations may reference the retired REST route explorer.hyperlane.xyz/api or a Hasura GraphQL URL. Use the endpoint on this page for new integrations; do not assume older endpoints support custom confirmations.