Skip to main content

API and live feed

The data API serves what the app itself reads: coins, trades, holders, market state and fee configuration. No account, no key, no agreement.

https://api.frontier.fun

Everything is served for Robinhood Chain, id 4663. Endpoints taking a chainId parameter default to it, so it can be omitted.

Quick start

curl 'https://api.frontier.fun/coinsPage?sort=volume24h&limit=1'
{
"data": [
{
"id": "0x4eCB998F7F7Fec237f9d6d6321038933669dd0cC",
"token": "0x4eCB998F7F7Fec237f9d6d6321038933669dd0cC",
"name": "great work",
"symbol": "GREAT",
"image": "ipfs://bafkreignslcu4pda3myluyggbix5td4dsmfsyi5726avpnhsu3nkuqsgl4",
"creator": "0x9cE7aA416E2c3E7cFd5F3f7c19Fe0201cd2235C9",
"launchKind": "curve",
"isLPd": false,
"price": "0.000000002466473546",
"marketCap": "1.032698723869568022",
"volume24h": 0.712236692171066,
"bondingProgress": 0.16956346471975636
}
],
"total": 11
}

The row is abridged here; the full shape is The coin row.

Conventions

Response envelopes

ShapeUsed by
{ "data": … }most reads
{ "success": true, "data": … }/coinCandles, /pools-v4/…/history/txs, /tokens
{ "data": [...], "total": n }the paginated listing
raw bytes/ipfs/{hash}

Types

KindEncoding
Addresses0x + 40 hex, accepted in any case — see Address casing
Pool idsbytes32, 0x + 64 hex
Coin and ETH amountsdecimal strings, already scaled out of wei
Prices, market capsstrings in ETH, or numbers where the field is a computed statistic
Volumesnumbers in ETH, except fields named USD
TimestampsUnix seconds
Imagesipfs://<cid> references, fetchable through /ipfs/{cid}
Basis points and pipsstrings of integers, as the contracts store them

Amounts are strings because they come straight from on-chain values and must not pass through a float. Statistics computed by the API, such as volume24h, are numbers by design.

Address casing

Send an address in whatever case you have it. Lowercase, checksummed or anything in between resolves to the same coin, the same wallet and the same answer, on every endpoint and in every parameter.

What comes back follows one rule:

  • An address field is EIP-55 checksummedtoken, creator, user, userAddress, stakingVault and the rest. That is the form to display, and the form an explorer or a wallet expects.
  • An address used as an object key is lowercase — the map in /tokens, the map in /vaults. A key is something you look up, so it has one spelling, and your own lookups do not have to guess.

Compare addresses case-insensitively anyway: it costs nothing and it survives a value arriving from somewhere else, a URL or a wallet among others.

Errors

{ "success": false, "error": "…" }

On a validation failure error is the validation report rather than a string, listing the offending parameters:

{
"success": false,
"error": {
"name": "ZodError",
"message": "[{ \"code\": \"invalid_value\", \"path\": [\"kind\"], … }]"
}
}
StatusMeaning
400A parameter is missing, malformed or out of range
404Unknown route
429Rate limited. A Retry-After header says when to come back
503An upstream read failed or the surface is not available on this chain. Treat it as "no data right now" and retry, never as an error state to show
500Unexpected. Worth reporting

Rate limits

Per IP, per minute:

TierLimitEndpoints
Standard120everything not listed below
Heavy30/coinCandles, /coins/{address}/extensions, and the four vault endpoints
Media600/ipfs/{hash}
Upload10/upload — it pins to our account

Caching

Answers are cached at the edge and carry their own Cache-Control. Polling faster than the cache window returns the same bytes.

EndpointCached
/coinsPage, /coinEvents, /recentActivity, /bondedActivity5s
/coinsStats15s
/coinsTop, /currentHighlight, /coinCandles30s
/highlights60s
vault and referral reads10s

Five seconds is the useful polling floor for the fast surfaces.

Objects

The coin row

Returned by /coinsPage and /coinsHydrate. It is card-complete: everything needed to render a coin, with no follow-up call.

FieldTypeNotes
id, tokenaddressThe coin's ERC-20 address, same value in both
name, symbolstring
imagestringipfs://…, may be empty
descriptionstringOnly when full=1 is asked of /coinsHydrate
creatoraddress
createdTimestampnumber
launchKindcurve | instantThe launch mode
isLPdbooleanWhether the coin is on its pool. With launchKind this gives the three trading phases
lpbytes32The pool id, once it exists
pricestringETH per coin. After graduation it follows the pool
price24hAgonumber | nullThe oldest price mark in the window, for the 24-hour change
marketCapstringETH
totalSupply, maxSupplystringCirculating and maximum
ETHReserves, targetETHstringCurve reserves and the raise target
curveAllocationstringCoins the curve sells before graduation
initialETHReserves, initialPricestringThe curve's starting point, frozen at creation
bondingProgressnumber | null0 to 1, on the reserves basis. null when the coin has no curve
volume24hnumberETH, curve and pool volume folded together
curveVolume24h, ammVolume24hnumberThe two halves, kept readable apart
volume24hAtnumberWhen the volume snapshot was computed
eventsCountnumberLifetime curve trades
lastActivityAtnumber
modulesarrayThe extensions bound to the pool: { id, name, kind }. Absent until the pool is indexed
feeKinddynamic | fixedWhether the pool runs the volatility fee or a flat one

Unknown fields may appear. Read by name and ignore the rest.

The trade event

Returned by /coinEvents, /recentActivity and /bondedActivity. Curve trades and pool swaps share one shape, so a single client can render both.

FieldTypeNotes
idstringUnique. {txHash}-{logIndex} on the curve, {txHash}:{poolId} on a pool
eventBuy | SellDirection from the trader's point of view
tokenaddress
useraddressThe trader
amountstringWhat went in: ETH on a buy, coins on a sell
amountOutstringWhat came out: coins on a buy, ETH on a sell
pricestringETH per coin right after the trade
timestampnumber
transactionHashstringCurve events
marketCap, totalSupply, reserveBalancestringCurve events, state right after the trade
bondedEventbooleantrue on pool swaps, absent on curve trades
name, symbolstringAdded by /recentActivity, so feed items stand alone

Discovery

GET /chains

The chain registry: RPCs, explorers, every contract address, the pool parameters, the curve defaults and bounds, and the indexing endpoints. Nothing should hardcode an address that this document serves. See Contracts and addresses.

curl https://api.frontier.fun/chains
[
{
"id": 4663,
"name": "Robinhood",
"type": "mainnet",
"rpcs": ["https://robinhood-rpc.publicnode.com", "…"],
"explorers": ["https://robinscan.io", "…"],
"native": { "symbol": "ETH", "decimals": 18, "wrapped": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73" },
"contracts": {
"tokenFactory": "0xe3A826C056e578c240D362BF4C2fa53E5c0c17a5",
"univ4": { "poolManager": "…", "quoter": "…", "hook": "…", "pool": { "fee": 8388608, "tickSpacing": 60 } }
},
"curveConfig": { "maxSupply": "1000000000000000000000000000", "…": "…" }
}
]

The response is an array: one entry per chain served.

GET /extensions

The extension catalog, fee calculators first. Each entry carries its own parameter schema, so an extension admitted to the catalog needs no client release to be configurable.

ParameterTypeDefault
chainIdnumber4663
{
"chainId": 4663,
"extensions": [
{
"id": "dynamic-fee",
"kind": "feeCalculator",
"name": "Dynamic Fee",
"status": "active",
"orderRank": 0,
"baseFeeProvider": true,
"incompatibleWith": ["maturity-curve"],
"configAbi": [
{ "key": "floorFee", "abiType": "uint24" },
{ "key": "midFee", "abiType": "uint24" },
{ "key": "capFee", "abiType": "uint24" }
],
"params": { "encoding": "abi", "fields": [] }
}
]
}

configAbi is the encoding of the extension's on-chain configuration, in order. status is active or coming-soon; an entry that is not active is listed but not bindable.

Coins

GET /coinsPage

One page of coins, sorted, filtered and searched server-side.

ParameterTypeDefaultNotes
sortenumactivityactivity, newest, oldest, marketcap, volume24h, trending (curve trades in the last 24h)
filterenumallall, new (created within 4 hours), bonded, trending, instant
orderenumdescasc walks each axis the other way
searchstringSubstring of the name or symbol, or an address prefix. 1 to 64 characters
offsetnumber0Up to 10000
limitnumber20Up to 100

Returns { data: [coin row], total }. total counts what the chosen axis can serve, so on volume24h it counts the coins that traded in the window. A search that hits its scan bound answers capped: true, meaning total is a floor.

On the mutable sorts a coin trading between two calls can cross a page boundary. Refetch the page rather than assuming offsets are stable.

GET /coinsHydrate

The same rows for a known set of coins: deep links, holdings, anything outside the paginated grid.

ParameterTypeDefaultNotes
addressesstringrequiredComma-separated, up to 100
full1Also resolve each coin's description

Unknown addresses are dropped from the answer rather than returned empty.

GET /coinsStats

{
"data": {
"total": 11,
"newTodayCount": 1,
"bondedCount": 0,
"totalVolume24h": 5.271701598958937,
"curveVolume24h": 4.917442490567309,
"ammVolume24h": 0.35425910839162805,
"totalVolumeAllTime": 37.20174364623039,
"volumeComputedAt": 1786898147,
"ethPriceUsd": 1882.30325411
}
}

Counts are exact and live. Volumes are recomputed about once a minute; volumeComputedAt stamps the snapshot. ethPriceUsd is the rate the app uses to show USD figures.

GET /coinsTop

ParameterTypeDefaultNotes
kindenumgainersgainers, or closest for the coins nearest to graduation
limitnumber10Up to 20

gainers entries carry price, price24hAgo and change as a percentage; closest entries carry progress from 0 to 1.

{
"data": [
{
"token": "0x4eCB998F7F7Fec237f9d6d6321038933669dd0cC",
"name": "great work",
"symbol": "GREAT",
"image": "ipfs://bafkreignslcu4pda3myluyggbix5td4dsmfsyi5726avpnhsu3nkuqsgl4",
"progress": 0.16956346471975636
}
]
}

GET /coinEvents

A coin's most recent curve trades, oldest first.

ParameterTypeDefaultNotes
tokenAddressaddressrequired
limitnumber100Up to 200

Only the newest 200 trades per coin are kept on this surface. For anything older, use the candles.

{
"data": [
{
"id": "0x5d97b25e…4017-5",
"event": "Buy",
"token": "0x86A3d4890Cd62a1d44E6EC3D405406Ee925674c1",
"user": "0x652BCfE9958cae3f0758a1D0376D501A73390e2E",
"amount": "0.005597",
"amountOut": "2230215.570191796250870861",
"price": "0.00000000247880742",
"marketCap": "1.043304581352876953",
"totalSupply": "420889728.235877619414878571",
"reserveBalance": "2.179145067268661814",
"transactionHash": "0x5d97b25e…4017",
"timestamp": 1786898871
}
]
}

GET /coinCandles

OHLC buckets for a coin's curve trading, oldest first, prices and volume in ETH. Computed from the full indexed history, not from the retained events, so it goes back to the first trade.

ParameterTypeDefaultNotes
tokenAddressaddressrequired
intervalnumber300Seconds: 30, 60, 300, 600, 1800, 3600, 14400, 86400, 2592000
limitnumber300Up to 500
chainIdnumber4663
{
"success": true,
"interval": 3600,
"data": [
{ "t": 1786892400, "o": 2.424213674e-9, "h": 2.424213674e-9, "l": 2.402081015e-9, "c": 2.411606836e-9, "v": 0.0209019 }
]
}

Buckets are sparse: an interval with no trade is absent rather than flat. Post-graduation price action is on the pool, not here.

GET /coins/{address}/extensions

The coin's live market configuration, read from the pool rather than from a cached row.

ParameterTypeDefault
addressaddress, in the pathrequired
chainIdnumber4663
{
"chainId": 4663,
"coin": "0x1Fa8978238b6A43A68B9F51Ac70b6E7526A38a8E",
"poolId": "0x724cb43a2106e72650a7690f97f29c1fc69ec8cdffc5188bc385d06305afc1bd",
"hookConfig": {
"lpShareBps": "1000",
"fixedFee": "15000",
"sniperWindow": "0",
"communityFeeRatio": "0",
"stakingVault": "0x0000000000000000000000000000000000000000",
"registeredAtTimestamp": "1786806129"
},
"protocolFeeRatio": "25",
"extensions": {
"feeCalculators": [
{ "address": "0xb96fBe3c…75D8", "known": true, "id": "dynamic-fee", "kind": "feeCalculator", "rawConfig": "0x…" }
],
"observers": []
}
}

fixedFee is in pips, lpShareBps and communityFeeRatio in basis points, sniperWindow in seconds. Lists keep their on-chain order. Each bound entry arrives joined against the catalog, with the raw on-chain configuration in rawConfig, decodable with the catalog entry's configAbi. An address the catalog does not list comes back as known: false. A coin with no pool yet answers poolId: null with empty lists.

protocolFeeRatio is read live rather than copied, because it is owner-settable. See Admin controls.

Holders, and per-wallet views

The holder distribution of a coin, the coins a wallet has traded and the coins it created are served for the app's own screens, on endpoints that are not part of this reference. They are per-request reads with no cache in front of them, so they are kept for the app rather than offered as an integration surface.

If your integration needs holder or per-wallet data, ask at [email protected] rather than reverse-engineering the app's calls: the shape it uses is not stable, and a documented one can be.

Activity and markets

GET /recentActivity

The most recent curve trades across every coin, newest first. limit up to 50, default 20. Items carry name and symbol so a feed row needs no lookup.

GET /bondedActivity

The same, for swaps on graduated coins' pools. A graduated coin stops producing curve trades, so a complete activity feed merges the two.

{
"data": [
{
"id": "0x00abf1f5…31cc:0x724cb43a…fc1bd",
"token": "0x1Fa8978238b6A43A68B9F51Ac70b6E7526A38a8E",
"event": "Sell",
"user": "0xf91D05Ec8B943634268748c1733984E13fe9963b",
"amount": "32483587.620178584",
"amountOut": "0.07564535770703193",
"price": "2.2493273178952734e-9",
"timestamp": 1786893734,
"bondedEvent": true
}
]
}

GET /pools-v4/{poolAddress}/history/txs

Recent swaps, adds and removes for one pool, addressed by pool id or by the pool address the app shows.

ParameterTypeDefault
poolAddresspool id or address, in the pathrequired
chainIdnumber4663
{
"success": true,
"data": [
{
"time": 1786893734,
"value": {
"type": "swap",
"account": "0xf91D05Ec8B943634268748c1733984E13fe9963b",
"token0Amount": "0.07564535770703193",
"token1Amount": "32483587.620178584",
"isFromToken0": false,
"fromToken": "mittens",
"toToken": "WETH",
"txHash": "0x00abf1f5…31cc",
"priceInEth": "2.2493273178952734e-9",
"totalValueUSD": "0.00"
}
}
]
}
Do not derive the price from the amounts

token1Amount / token0Amount includes the swap fee, and a Frontier pool sets its own fee, which can be high and can move between blocks. Use priceInEth, the price at the pool right after the swap, the same figure the candles and the activity feeds carry.

GET /tokens

24-hour volume in USD per coin, keyed by lowercase address.

{
"success": true,
"data": {
"error": null,
"tokens": {
"0x1fa8978238b6a43a68b9f51ac70b6e7526a38a8e": {
"address": "0x1Fa8978238b6A43A68B9F51Ac70b6E7526A38a8E",
"oneDayVolumeUSD": 0
}
}
}
}

Staking vaults

GET /vaults

Every staking vault, keyed by lowercase vault address, each with its coin, total staked assets, cooldown in seconds, and its events.

{
"data": {
"0x2dcc79ed57e8b90ae144e75e896b353687525c28": {
"id": "0x2DCC79ED57e8B90AE144E75e896B353687525C28",
"vault": "0x2DCC79ED57e8B90AE144E75e896B353687525C28",
"bcToken": "0x8fBDe5D76f24e73667E1be2B095fD8DF560E6fF6",
"totalAssets": 0,
"cooldownDuration": 86400,
"events": []
}
}
}

GET /vaultByToken

One vault, by tokenAddress. data is null when the coin has no vault.

GET /vaultEventsByToken

That vault's events by tokenAddress: deployment, deposits, withdrawal requests and claims, each with vault, user, assets and timestamp.

GET /vaultPositionByUserVault

One staker's position. Requires userAddress and vaultAddress; answers null when there is none.

FieldType
user, vaultaddress
currentDepositAmountstring, coins staked
pendingWithdrawAmountstring, coins in cooldown

Referrals and highlights

GET /referralRewards

Referral rewards earned by userAddress: referrer, referredUser, amount, token, timestamp.

GET /referralPayouts

Referral payouts received by userAddress: referrer, amount, timestamp.

GET /highlights · GET /currentHighlight

Recent highlights, and the one running now, or null. Entries carry token, buyer, amount and bookedUntil. Booking is not open yet, so both answer empty today.

Media

POST /upload

Pins an image to IPFS and returns its CID, so a launch made by calling the factory directly can carry a real logo instead of the placeholder. It needs no wallet and no key — a launch legitimately happens before a wallet is connected.

Send exactly one of:

  • image — a base64 data URL. The bytes are checked against the type you declare (magic bytes, or a structural check for SVG), so a mislabelled file is rejected rather than pinned.
  • imageUrl — a public http(s) URL; we fetch it server-side. Plain public hostnames only (no literal IPs, no localhost, nothing of ours), at most 3 redirects — each hop re-checked against the same rules — and the type is read from the fetched bytes, not from the server's headers.

Either way: PNG · JPEG · GIF · WebP · SVG, 2 MB maximum — for a URL the cap is enforced while downloading, so pointing us at something huge just cuts the transfer.

curl -X POST https://api.frontier.fun/upload \
-H 'Content-Type: application/json' \
-d '{"image":"data:image/png;base64,iVBORw0KGgo...","name":"my-coin"}'

# or, if the image already lives at a URL:
curl -X POST https://api.frontier.fun/upload \
-H 'Content-Type: application/json' \
-d '{"imageUrl":"https://example.com/my-logo.png","name":"my-coin"}'
{ "ipfsHash": "bafkreignslcu4pda3myluyggbix5td4dsmfsyi5726avpnhsu3nkuqsgl4" }

name is required and only labels the pin — omitting it is a 400, and anything past 128 characters is trimmed. Pass the CID to deploy() as the image argument, either bare or as ipfs://<cid> — both resolve.

StatusMeaning
400A field is missing, both forms were sent at once, or the URL points somewhere we refuse to fetch
413Over 2 MB
415Not one of the five accepted types, or the bytes contradict the type declared
502The URL could not be fetched, or pinning failed — retry; nothing was stored
429Over the rate limit below; retry after a minute
502The pinning service failed — never a 200 with a missing CID

Rate-limited to 10 per minute per IP — it pins to our account, so it is the tightest bucket on the API. If you already hold the image at a URL, you still have to fetch and encode it yourself for now.

note

Uploading is not what makes the image survive. The CID is adopted by our own pinning when the deployment is indexed — but if you pin the image elsewhere and it lapses there before that happens, the bytes are gone for good while the CID stays on-chain forever. Uploading here first is the safe order.

GET /ipfs/{hash}

Fetches a CID through the gateway, streamed and cached immutably. Coin rows carry ipfs://<cid>; swap the prefix for this endpoint. The path accepts a bare CID and nothing else. Content larger than 2 MB — the same bound as /upload — is refused with a 413: a coin image is at most 2 MB however it arrives on-chain.

https://api.frontier.fun/ipfs/bafkreignslcu4pda3myluyggbix5td4dsmfsyi5726avpnhsu3nkuqsgl4

Calling it from a browser

The API is meant to be called server-side. Only the app's own origins are on the cross-origin allow list, so a page hosted elsewhere cannot call it from the client. Proxy it through your own backend, which also lets you cache and rate-limit for your users.

The live feed

The app holds a WebSocket open and receives trades, deploys, graduations and vault events as they happen, roughly a tenth of a second behind the write that records them, with a short replay on reconnect so nothing is missed across a blip.

It is not open to third-party clients yet. Connections are accepted from the app's own origins, and the message protocol is not stable enough to publish. Until it is, the polling equivalent is /recentActivity and /bondedActivity merged newest-first, both refreshed every five seconds, plus /coinsPage for the state of the grid.

If a push feed is what your integration needs, say so at [email protected]. Access is a question of readiness, not of policy.

Guarantees

  • The chain is the authority. Everything here is indexed from it. A trade is final when it is on-chain, not when it appears in a response.
  • Nothing is authenticated, so nothing served is private. Every figure comes from public state.
  • Event ids are stable and unique. Deduplicate on id rather than on position; a feed can re-deliver an item.
  • Ordering is by timestamp, newest first on the feeds, oldest first on /coinEvents and the candles. Two trades in the same block can arrive in either order.
  • Counters and volumes are snapshots, recomputed about once a minute, and the response says when.
  • Shapes are additive, not versioned. Fields get added; read by name and ignore what you do not know.

Anything unclear, or a shape you need that is not served: [email protected].