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 theid 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
Destination transaction details and delivery timestamps can benull 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
Setconfirmations 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.
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 inchains/<chain-name>/metadata.yaml in the Hyperlane Registry, for example Ethereum or Base:
blocks.reorgPeriodconfigures the scraper’s canonical confirmation boundary. It can be a numeric delay or a chain-specific finality selector, such as a block tag.blocks.confirmationsis a separate transaction-confirmation setting; it is not the Explorer API’s default confirmation delay.
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 withorder_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 acceptconfirmations. Prefer filters on chain, message, or time over repeated full-history counts.
Chains: domain
Results are underdata.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:
byteavalues use a literal\xprefix followed by hexadecimal bytes. In JSON or JavaScript string literals, escape the backslash as"\\x...". Convert a0x-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:
bigintandnumericvalues are returned as strings. Preserve their precision withBigIntfor 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_latencyis 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/_ninlists 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_idusing_eqor_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
nullfor that field alongside successful results for other query fields. Handleerrorsbefore 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.
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.