For buyers

API documentation

Free endpoints (coverage, discovery, availability) let you decide what to buy. Data endpoints return HTTP 402 Payment Required (x402 v2) until you pay with a signed authorisation, in USDC. Pay on Base, where the facilitator pays the gas, or directly on Hyperliquid with the same USDC you trade with (gasless).

Base URL: https://api.hyperextend.xyz

Discover before you pay

All free, all unauthenticated: check what's available and how deep before spending anything.

EndpointAnswers
GET/v1/discovery What's available at a glance: dex/coin counts, intervals, availability lag.
GET/v1/intervals Supported candle interval labels, 1m through 1d.
GET/v1/dexes Every dex (main, HIP-3 perps and HIP-4 outcome markets) with first/last seen.
GET/v1/dexes/{dex}/coins The active universe on a dex.
GET/v1/dexes/history Full HIP-3 dex appearance log: listed / delisted / deployer-changed, oldest first.
GET/v1/coins/{coin} Which dexes a coin trades on.
GET/v1/coins/{coin}/history Listing / delisting / leverage-change log over time.
GET/v1/outcome_markets?start=&end= HIP-4 outcome markets trading in a window (epoch-ms, both optional). Each market's name plus the side coins and outcome id you use to buy candles, ctx (asset context: funding, mark, oracle and similar fields) or OI (open interest).
GET/v1/availability/{coin} Per-dex first/last for ctx and candles.
GET/v1/coverage/{coin}?start=&end=&dex= Gap manifest for OI / ctx over a window. dex defaults to main.
GET/v1/candles/{coin}/coverage?start=&end=&dex= Gap manifest for candles over a window (≤31 days). dex defaults to main.
GET/v1/trades/discovery?coin= Trades model: served-live, archive floor, window cap, pricing; ?coin= adds hot first/last.
GET/v1/trades/cache Archive hours already warm in the cold cache, as coalesced windows; read inside them and the cold-pull fee never applies (trades and liquidations share the cache).
GET/v1/liquidations/discovery?coin= Liquidations model: archive floor, about 2 hours' lag, window cap, pricing; ?coin= adds dex and rate.
POST/v1/mailing/subscribe JSON mailing signup for agents (body {"email"}); returns a confirm token inline (POST /v1/mailing/confirm with it to activate). Double-opt-in archive updates.
POST/v1/mailing/unsubscribe JSON unsubscribe for agents (body {"email", "token"}, the same token subscribe returned). Wrong token or unknown email → 404.

The payment flow

We speak x402 v2, so use Coinbase's official x402 client. It does the whole dance for you: GET → 402 challenge (in the PAYMENT-REQUIRED header) → sign an EIP-3009 authorisation → retry with the PAYMENT-SIGNATURE header → 200. You only need USDC on Base; the facilitator pays gas and the receipt returns in PAYMENT-RESPONSE.

Python (official x402 client)

python · exact
# pip install "x402[evm]"  (Coinbase's official x402 client; handles 402 -> pay -> retry)
import asyncio
from eth_account import Account
from x402 import x402Client
from x402.mechanisms.evm import EthAccountSigner
from x402.mechanisms.evm.exact.register import register_exact_evm_client
from x402.http.clients import x402HttpxClient

async def main():
    client = x402Client()
    register_exact_evm_client(client, EthAccountSigner(Account.from_key(MY_PRIVATE_KEY)))
    url = "https://api.hyperextend.xyz/v1/candles/BTC/1m?start=1748736000000&end=1748822400000"  # a 1-day window with data
    async with x402HttpxClient(client) as http:
        r = await http.get(url)        # pays automatically; needs USDC on Base
        candles = (await r.aread()) and r.json()

asyncio.run(main())

x402HttpxClient reads the challenge, signs with your key, and retries automatically, with no protocol code to hand-roll. There's a matching JS/TS client too.

Or pay on Hyperliquid (HyperCore)

The 402's accepts also offers a hyperliquid:mainnet rail. Pay directly with the same USDC you trade and open positions with on Hyperliquid: no bridging, no second wallet, no gas. There's no facilitator; you sign a HyperliquidTransaction:SendAsset with the hyperliquid SDK, echo the quoted amount verbatim, and retry with PAYMENT-SIGNATURE; HyperCore settles it gaslessly. Pay from your spot or perps balance; Hyperliquid's unified account means one USDC funds both.

Or pay once, then stream (batch settlement)

For high-throughput use (many small calls in a row), Base also offers a batch-settlement scheme in accepts (alongside exact). Instead of settling on-chain every request, you deposit USDC into an escrow once. After that you pay per request with a cumulative off-chain voucher. Each voucher is verified off-chain, so there's no per-request on-chain transaction and the reply is almost instant. Verification includes our own check of its signature against your payerAuthorizer, the address of the key that signs your vouchers (see below).

After your purchase, our keyless channel manager claims your latest voucher on-chain. Because each voucher is cumulative (it carries your running total), you never over-pay. The manager stays keyless, because Coinbase Developer Platform (CDP) holds the claiming key and pays the gas. It is opt-in, and you only need USDC on Base (no ETH), since CDP gasses the deposit and claim.

  1. Deposit once (request 1). The first paid call opens a payment channel. The client deposits USDC into the escrow on Base: a multiple of the request price, set by the deposit_multiplier below. That multiple is what lets one deposit cover a run of calls. CDP broadcasts and gasses it; you sign, you don't pay gas.
  2. Stream vouchers (requests 2…N). Each subsequent call is a purely off-chain signed voucher carrying the growing cumulative maxClaimableAmount. It's verified off-chain and the data comes back immediately, with no on-chain round-trip.
  3. We claim your voucher. After your purchase, our keyless channel manager claims your latest voucher on-chain, paying it to payTo. Because the voucher is cumulative, you never over-pay. CDP pays the gas.
  4. Refund the remainder. Spent less than you deposited? Ask for a cooperative refund with the client's refund call. Or start a withdrawal from the escrow contract yourself: the withdrawal completes after the channel's withdrawal delay (24 hours). A fully-spent channel simply has nothing to return.

Register only the batch-settlement scheme and the official x402[evm] client selects it from the 402's accepts and handles the deposit and vouchers for you:

python · batch-settlement
# pip install "x402[evm]"  (register ONLY batch-settlement so the client picks it over exact)
import asyncio, httpx
from eth_account import Account
from x402 import x402Client
from x402.http.clients import x402_httpx_transport
from x402.mechanisms.evm import EthAccountSignerWithRPC
from x402.mechanisms.evm.batch_settlement.client import (
    BatchSettlementEvmScheme, BatchSettlementEvmSchemeOptions,
    BatchSettlementDepositPolicy, InMemoryClientChannelStorage,
)

async def main():
    signer = EthAccountSignerWithRPC(Account.from_key(MY_PRIVATE_KEY), rpc_url="https://mainnet.base.org")
    # A private-key wallet needs nothing extra: payerAuthorizer defaults to this signer's address.
    scheme = BatchSettlementEvmScheme(signer, BatchSettlementEvmSchemeOptions(
        deposit_policy=BatchSettlementDepositPolicy(deposit_multiplier=5),  # escrow = 5x the request price
        storage=InMemoryClientChannelStorage(),
    ))
    client = x402Client().register("eip155:*", scheme)   # batch-settlement only -> chosen over exact
    url = "https://api.hyperextend.xyz/v1/candles/BTC/1m?start=1748736000000&end=1748822400000"  # a 1-day window with data
    async with httpx.AsyncClient(transport=x402_httpx_transport(client)) as http:
        for _ in range(100):              # request 1 opens the channel (on-chain deposit); the rest are vouchers
            r = await http.get(url)       # ~instant, no per-request on-chain tx
            candles = (await r.aread()) and r.json()

asyncio.run(main())

For a private-key wallet, the snippet above is the whole integration: the official x402[evm] client opens the channel and signs the vouchers for you. Best when you'd otherwise make hundreds of per-request settles; for the occasional call, plain exact is simpler.

Set a non-zero payerAuthorizer before you use batch settlement

A batch-settlement channel must name a non-zero payerAuthorizer: the address of the key that signs your vouchers. Vouchers from a channel whose payerAuthorizer is the zero address are refused with a 402.

  • Private-key (EOA) wallet: nothing to do. The x402 client sets payerAuthorizer to your signing key's address by default, so the example above works as it is.
  • Smart-contract wallet: pass a separate plain signing key you control as the voucher signer. In Python that's BatchSettlementEvmSchemeOptions(voucher_signer=...); in TypeScript, { voucherSigner }. Its address becomes the payerAuthorizer.

The payerAuthorizer must be the address of your own key, never hyperextend's. If you can't or won't set one, the exact scheme on Base and on HyperCore stays open to you. Upstream details: wallet compatibility (the "Batch-settlement vouchers" section) and the TypeScript batch-settlement client (the "Voucher Signer Delegation" section).

Endpoints

EndpointNotes
GET/v1/candles/{coin}/{interval}?start=&end=&dex= Historical OHLCV (open, high, low, close, volume) candles for a coin & interval over a time window. dex defaults to main; set spot, a HIP-3 dex name (e.g. xyz), or outcome for HIP-4. Base rate on main & spot, premium elsewhere.
GET/v1/candles/{coin}/{interval}/latest?n=&dex= The most recent n candles, a cheap recent-window convenience. dex as above.
GET/v1/asset_ctx/{coin}?start=&end=&dex= Open interest / funding / mark / oracle / mid / volumes. Premium rate. dex defaults to main; set spot or a HIP-3 dex name.
GET/v1/asset_ctx/{coin}/latest?n=&dex= The most recent n OI / ctx snapshots, a cheap recent-window convenience. Premium rate. dex as above.
GET/v1/outcome_ctx/{coin}?start=&end= HIP-4 outcome-side mark / mid / circulating supply / volumes. Premium rate; served live (no lag).
GET/v1/outcome_ctx/{coin}/latest?n= The most recent n outcome-side snapshots. Premium rate; served live.
GET/v1/outcome/{outcome}/oi?start=&end= Derived two-sided open interest for a HIP-4 outcome market, per minute. Premium rate; served live.
GET/v1/trades/{coin}?start=&end= Raw trade tape, mirroring Hyperliquid's WsTrade verbatim: coin, side, px, sz, time, hash, tid and users:[buyer, seller]. Priced per asset-hour (not per row); HIP-3 / HIP-4 premium. Each uncached archive hour pulled adds a $0.05 cold-pull charge and warms the cache for everyone after.
GET/v1/trades/coverage?coin=&start=&end= Archive coverage for a coin over a window (≤7 days): which hours have trades and the gaps. Warms the cache. Priced floor plus $0.05 per archived hour examined.
GET/v1/liquidations/{coin}?start=&end= Forced-liquidation tape: a trade row (coin, side, px, sz, time, hash, tid, users:[buyer, seller]) plus the liquidation markers (method, markPx, liquidatedUser, dir) over a window. Archive-derived (no public Hyperliquid feed; about 2 hours' lag). Priced per asset-hour at a third of trades; plus $0.05 per uncached archive hour pulled (warms the cache).
GET/v1/liquidations/coverage?coin=&start=&end= Archive coverage for a coin's liquidations over a window (≤7 days): which hours have liquidations and the gaps. Warms the cache. Floor plus $0.05 per archived hour examined.

Pricing

Two-part tariff: cost = floor + rows × per_row, billed per row returned. The per-row rate is tiered by what the data is.

Floor
$0.001 / request

Charged on every request, before any rows.

Base · per row
$0.00001

Main-perp & spot candles.

Premium · per row
$0.000025

Open interest, HIP-3 perps, HIP-4 outcome markets.

Premium is the data Hyperliquid keeps no history of. Responses are paginated: walk wider ranges with the X-Next-Start cursor returned in the response headers.

RequestCost
100 main / spot candles (base)$0.002
1 day of 1m candles (1,440 rows, base)$0.0154
100 rows of OI / outcome data (premium)$0.0035
1 day of 1m candles on a HIP-3 / outcome dex (premium)$0.037

Trades

Each trade row mirrors Hyperliquid's WsTrade verbatim: coin, side, px, sz, time, hash, tid and users:[buyer, seller] (the counterparty addresses Hyperliquid's own feed carries). The raw tape is priced per asset-hour (one (coin, hour) bucket, which can hold thousands of fills) rather than per row. HIP-3 / HIP-4 are premium. Each uncached archive hour a request pulls adds a per-hour cold-pull charge (it reconstructs that hour from the archive and warms the cache, so already-cached hours don't re-charge):

tariff · trades
cost = floor + asset_hours × per_asset_hour  (+ cold-pull × uncached_hours)
floor          = $0.001  per request
per_asset_hour = $0.015  base     (main & spot)
               = $0.03   premium  (HIP-3 perps & HIP-4 outcomes)
cold-pull      = $0.05   per uncached archive hour pulled (warms the cache for everyone after)
RequestCost
1 hour of BTC trades (base, cached)$0.016
1 day of BTC trades (24 asset-hours, base, cached)$0.361
1 hour of a HIP-3 / outcome coin (premium, cached)$0.031
1 uncached archive hour (base plus cold-pull)$0.066

Archive coverage: GET /v1/trades/coverage?coin=&start=&end= (≤7-day window) reports which archived hours hold a coin's trades and where the gaps are, and warms the cache for everyone after. Priced $0.001 + $0.05 × archived hours examined (the same per-hour cold rate as a read's cold-pull). See what's already warm for free: GET /v1/trades/cache lists the cached archive hours as coalesced windows; a read wholly inside them pays only the per-asset-hour rate, never the cold-pull. Warm hours are exchange-wide (every coin) and shared with liquidations.

Liquidations

The forced-liquidation tape (GET /v1/liquidations/…) is the same per asset-hour model as trades but a third of the rate: liquidations are sparse, so an hour holds far fewer rows. Each row is a full trade row (coin, side, px, sz, time, hash, tid, users:[buyer, seller]). Each row also carries the liquidation markers (method market | backstop, markPx, liquidatedUser, which of the two users was force-closed, and dir). Hyperliquid publishes no liquidations feed at all, so this is reconstructed from the node-fills archive:

tariff · liquidations
cost = floor + asset_hours × per_asset_hour  (+ cold-pull × uncached_hours)
floor          = $0.001  per request
per_asset_hour = $0.005  base     (main & spot)
               = $0.01   premium  (HIP-3 perps & HIP-4 outcomes)
cold-pull      = $0.05   per uncached archive hour pulled (warms the cache for everyone after)
RequestCost
1 hour of BTC liquidations (base, cached)$0.006
1 day of BTC liquidations (24 asset-hours, base, cached)$0.121
1 hour of a HIP-3 / outcome coin (premium, cached)$0.011
1 uncached archive hour (base plus cold-pull)$0.056

Archive-derived: there's no live tier (no public feed exists), so liquidations are available about 2 hours after the hour closes. GET /v1/liquidations/coverage?coin=&start=&end= reports which archived hours hold a coin's liquidations and where the gaps are, and warms the cache for everyone after.

Network & USDC

Here a rail is the network you pay on, and a scheme is how you pay on it (exact or batch-settlement). The accepts array advertises what this deployment takes: the Base and Hyperliquid rails, with Base offering both the per-request exact scheme and the opt-in batch-settlement scheme. Always confirm the exact asset and (for Base) the EIP-712 domain from accepts[].asset / accepts[].extra rather than hardcoding them.

Rail · schemeIdentifierUSDC
Base (EVM) · exact eip155:8453 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
Base (EVM) · batch-settlement eip155:8453 · scheme batch-settlement 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
Hyperliquid (HyperCore) · exact hyperliquid:mainnet USDC:0x6d1e7cde53ba9467b783cb7c530ce054

Data freshness

Candles are served up to roughly 2 days ago, the archive's freshness horizon. For more-recent candles, go straight to the source: Hyperliquid's own API natively serves the latest candles.

Need anything fresher than a product's window? Query Hyperliquid's info endpoint directly. It serves recent candles and live state. hyperextend keeps the deep, per-minute history.

  • Candle reads clip end to the cutoff; responses carry an X-Data-Cutoff-Ts header.
  • GET /v1/discovery reports the current availability_lag_minutes (candles) and asset_ctx_availability_lag_minutes (OI, 0 = live).
  • Newer candles → Hyperliquid's info endpoint.

Open interest / asset-context is served live, with no 2-day lag. Hyperliquid exposes no OI history endpoint, so our per-minute archive is the only source. We serve it right up to the captured edge, and /v1/coverage shows exactly which minutes are present. Same posture as the HIP-4 outcome series.

Trades are served live too, with no 2-day lag. The raw tape is served live. A hot store holds roughly the last 24 hours as fills are captured. We merge that store transparently with an S3 archive reaching back to the start of our trade history (mid-2025). You don't pick a tier: a single request spans both, so trades cover everything from moments-old to the archive floor.

  • Each request is capped to a 24-asset-hour window (one asset-day for a single coin); for longer spans, paginate by day; a wider window returns 400.
  • Each uncached archived hour a request pulls adds the $0.05 cold-pull charge (see Pricing) and warms the cache for everyone after.
  • GET /v1/trades/cache (free) shows which archive hours are already warm: windows you can read with no cold-pull charge at all.

Liquidations, by contrast, are archive-derived. Hyperliquid exposes no liquidations feed of any kind, so there's no live tier. We reconstruct the forced-liquidation tape from the node-fills archive, and it is available about 2 hours behind. A request clamps to that horizon. Same 24-asset-hour cap and per-hour cold-pull as trades.