# API reference

All endpoints are under `https://www.pangea.trade/api`, take and return JSON, and need no key or account. The general rules are in [For integrators](https://www.pangea.trade/app/docs#integrators), which also describes five of them in full: pools, history, bridge activity, token metadata and the bridge quote. The relayers’ price board is in [Relayers](https://www.pangea.trade/app/docs#relayers). This section lists all of them and describes the rest.

- An error is `{ "error": "..." }` with a 4xx status (a 5xx is a fault, and its body may be a proxy's own). A value the chains could not give is `null`, not a guess.
- Limits are per caller, by IP address, counted on each server. Over a limit the answer is `429` and the message says how many seconds to wait; some also send `Retry-After`.
- A JSON body that is too large is `413`, one that is compressed is `415`, one that does not arrive within 10 seconds is `408`, and one that is not a JSON object of the expected fields is `400`.
- Amounts are base units as decimal strings. Chains are named `ethereum`, `base`, `robinhood`, `bsc` and `solana`. A launch is named by its slug.
- Three endpoints answer as a stream of server-sent events: `data: <json>` lines, with `content-type: text/event-stream`. Read them with a streaming fetch; they are POST, so an `EventSource` cannot open them.

## Every public endpoint

| Endpoint | What it is for | Limit per caller |
| --- | --- | --- |
| `GET /pools` | Every launch and its pool on each chain. | None; one shared reading. |
| `GET /history` | Trades, volume and price candles. | 30 in ten minutes, uncached reads only. |
| `GET /holders` | Who holds a token, per chain. | 60 in ten minutes, uncached reads only. |
| `GET /token/meta` | A token’s metadata document. | None. |
| `GET /logo/[cid]/[file]` | A token’s logo from this site, as square WebP: the file is 64.webp, 128.webp or 256.webp, and the CID is the image’s own, as /token/meta names it. Cached for a year: a CID’s picture cannot change. | None. |
| `GET /platform-funds` | The platform’s fee balance on each chain, in native units and US dollars, with the total: what is waiting to buy and burn PANGEA. | None; one shared reading a minute. |
| `GET /bridge/activity` | Recent transfers between chains. | None. |
| `GET /bridge/balance` | One address’s balance of a token or the native asset. | 120 in ten minutes |
| `POST /bridge/quote` | A transfer priced, both lanes, with the transaction to sign. | 120 in ten minutes, 15 a minute. |
| `POST /bridge/solana-tx` | The unsigned transaction for a transfer out of Solana. | 60 in ten minutes, 10 a minute. |
| `POST /bridge/solana-fast-tx` | The same, as a fast order. | 60 in ten minutes, 10 a minute. |
| `POST /bridge/route-open` | Opens a Solana route once its setup payment has landed. | 120 in ten minutes |
| `POST /bridge/arrival` | A stream that says when a transfer has arrived. | 60 in ten minutes |
| `POST /bridge/refund` | Whether a fast order is held, and the transaction that sends it back. | 60 in ten minutes |
| `POST /bridge/orders` | Tells the board a fast order was posted at a relayer’s price. | 60 in ten minutes |
| `GET, POST /bridge/relayer-quotes` | The relayers’ price board. | 300 in ten minutes reads, 120 publishes. |
| `POST /chain/tx` | A stream that says when a transaction is in a block. | 60 in ten minutes |
| `POST /trade/quote` | A buy or sell priced through Relay, or Jupiter on Solana. | 60 a minute. |
| `POST /trade/solana-tx` | Compiles a swap’s Solana instructions into an unsigned transaction. | 60 in ten minutes |

> **Note:** The launch endpoints are for the launch page and are not described here: preparing a launch only answers the Pangea site, and the rest belong to its steps.

## GET /holders

- Holders, GET: `https://www.pangea.trade/api/holders`

Query: `token`, a slug, required; `chain`, optional, to answer for one chain. The answer is `{ slug, readAt, launchTotal, chains, all }`, where each of `chains` is `{ chain, count, top10Pct, rows, complete, note?, error? }` and each row `{ chain, address, balance, pct, label }`, balances in whole tokens, at most 100 rows a chain. `all` combines the chains, `{ rows, count, partial, top10Pct }`, and is left out when `chain` is given. `label` names a known holder such as the pool or the bridge escrow. An answer is reused for a minute. Errors: `400` without a token, `404` for an unknown launch or a chain it is not on.

## GET /bridge/balance

- Balance, GET: `https://www.pangea.trade/api/bridge/balance`

Query: `token` (slug), `chain` and `address`, all required, and `asset=native` to read the chain’s native asset instead of the token. The answer is `{ slug, chain, address, balance, decimals, reason?, reserve? }`: `balance` in base units as a string, or `null` with a `reason` when the chain could not be read, never a false zero. On Solana the token balance is the sum of the owner’s token accounts for the mint. For the native asset, `reserve` is the gas the app keeps back for a trade. Errors: `400` for a missing field or an address of the wrong kind, `404` for an unknown launch or chain.

## POST /bridge/quote, in full

Beyond the fields in [For integrators](https://www.pangea.trade/app/docs#integrators), the body may carry `slippageBps` for the fast lane, 50 unless given and 1000 at most, and `smartWallet`, true when the sender is a contract wallet. The answer’s `routes` holds two routes, `canonical` and `fast`, and a route that cannot be used says why in `unavailable`. Besides the fields listed there, a route may carry:

| Field | What it is |
| --- | --- |
| `label` | `Standard` or `Fast`. |
| `fastFee`, `relayerFee`, `relayer` | On the fast route: the fast lane’s fee, the relayer’s price and who it is, in base units. |
| `minReceived` | On the fast route: the least the order lets the recipient be paid. |
| `approval` | On the fast route from an EVM chain: the approval to send first, `{ to, data, value, chainId }`, or null when none is needed. |
| `solanaFast` | On the fast route out of Solana: `{ relayerFee, minReceived }`, for `/bridge/solana-fast-tx`. |
| `routePayment` | From an EVM chain into a Solana route that is not open: the one-time setup payment, `{ to, data, value, chainId }`, to send before the transfer. |
| `setupNote`, `messageFeeLater` | Out of Solana with a route to open: the setup is paid first and LayerZero’s fee is priced after it. |
| `feeIsMaximum` | `nativeFee` is the most the Solana transaction will sign; LayerZero charges what its workers quote. |
| `note` | A sentence about the route, for showing to a person. |

Further errors: `409` when the token has not launched on the destination, `424` when a Solana recipient could not be checked, and `424` with `retry: true` when pricing took longer than 45 seconds.

## POST /bridge/solana-tx

- Out of Solana, POST: `https://www.pangea.trade/api/bridge/solana-tx`

The body you POST:

```json
{
  "slug": "<launch slug>",
  "to": "base",
  "amount": "1000000000000",
  "sender": "<Solana wallet>",
  "recipient": "0x<EVM address>"
}
```

Builds the unsigned transaction that sends the token from Solana to an EVM chain, for the sender to sign. `after` and `afterValidUntil` are given only on a second call after a setup step. The answer carries the request’s `from`, `to`, `amount` and `symbol` and one of three stages:

| Stage | What to do |
| --- | --- |
| `send` | Sign `transaction`, a base64 versioned transaction, and send it. `received` is what arrives, `nativeFee` LayerZero’s fee and `nativeFeeCap` the most it will sign. |
| `together` | The same, with the route’s opening in the same transaction. `setupFee` is the opening’s part of `totalFee`. |
| `setup` | The opening alone. Sign and send it, then call again with `after` set to its signature for the send. |

Every stage carries `blockhash` and `lastValidBlockHeight`: sign within about a minute. While a setup step is still settling the answer is `202` with `{ pending: true, stage: "waiting" }`; ask again. Errors: `400` for a bad field or a signature that is not this transfer’s setup, `404` for an unknown launch, `409` when the setup ran out or failed, the route is unusable or the wallet is short of SOL, `424` when the build takes longer than usual, with `retry: true`, and `424` after 50 seconds.

## POST /bridge/solana-fast-tx

- Fast out of Solana, POST: `https://www.pangea.trade/api/bridge/solana-fast-tx`

The fast lane out of Solana: one unsigned transaction holding Pangea’s fast-bridge order and the OFT send that carries it. Body: `{ slug, to, recipient, amount, relayerFee, minReceived, sender }`, with `relayerFee` and `minReceived` from the quote’s `solanaFast`. The answer is `{ stage: "send", transaction, orderId, amount, arriving, fastFee, relayerFee, nativeFee, nativeFeeCap, blockhash, lastValidBlockHeight }`. Errors: `409` when the fast lane is off for this launch or route, `422` when the order could not be built, nothing having been sent.

## POST /bridge/route-open

- Open a Solana route, POST: `https://www.pangea.trade/api/bridge/route-open`

The second step of the first transfer from an EVM chain into a Solana route: once the quote’s `routePayment` has been sent, this hands its transaction to Pangea’s delivery service, which checks the payment on chain and opens the route, or refunds it. Body: `{ slug, from, txHash, sender }`, `from` being the EVM chain the payment was made on. With `Accept: text/event-stream` it streams `{ state, reason?, refundTx? }` as the route is opened; otherwise it answers once. `state` is one of `verifying`, `paid`, `opening`, `open`, `refunded`, `refund-owed`, `review` and `refused`. Send the transfer once it is `open`. Errors: `404` for a launch not on Solana, `424` when routes cannot be opened from this deployment.

## POST /bridge/arrival

- Arrival stream, POST: `https://www.pangea.trade/api/bridge/arrival`

Body: `{ txHash }`, the send’s transaction hash or Solana signature. A stream of `{ state, route, guid, dstTx?, by? }`, `state` being `in-flight` and then `delivered`, with the delivery’s transaction in `dstTx`. It is fed by Pangea’s delivery service, which remembers a transfer for 30 minutes. Errors: `400` for a malformed hash, `424` when the deployment does not serve arrivals; LayerZero Scan answers the same question.

## POST /bridge/refund

- Held fast orders, POST: `https://www.pangea.trade/api/bridge/refund`

Body: `{ chain, orderId }`, the destination chain and the fast order’s id. The answer is `{ held: false }` or `{ held: true, guid, amount, srcEid, call }`, where `call` is the `refund(guid)` transaction, `{ to, data, value, chainId }`, with LayerZero’s fee for the trip back as its value. It looks back 5,000 blocks. Errors: `400` for a malformed id or a chain without a fast bridge.

## POST /bridge/orders

- Report a fast order, POST: `https://www.pangea.trade/api/bridge/orders`

Body: `{ from, hash }`, the chain a fast order was posted on and its transaction. The board reads the order from the receipt and remembers whose price it was sent at, which is how a relayer that does not fill is benched. The answer is `202` with `{ recorded: false, pending: true }` before the receipt exists, then `{ recorded, relayer, why?, orderId, to, srcBridge }`. Only orders priced from this deployment’s board are recorded; `why` says why not.

## POST /chain/tx

- Transaction stream, POST: `https://www.pangea.trade/api/chain/tx`

Body: `{ chain, hash }`. One event when the transaction is in a block: `{ state: "mined", success, block }` on an EVM chain, `{ state: "mined", success }` on Solana, or `{ state: "unseen" }` if it never appears, after up to 10 minutes on an EVM chain and 5 on Solana.

## Trading: POST /trade/quote and POST /trade/solana-tx

These are the trade card’s, as they are in release r41, and are due to change. `/trade/quote` takes `{ slug, side, chain, amount, fromChain?, user?, solanaUser?, recipient?, slippageBps? }`: `side` is `buy` or `sell`, `chain` a chain name or `auto` for the cheapest chain to buy on or the dearest to sell on, and `amount` the native asset’s base units for a buy, the token’s for a sell. `slippageBps` is the slippage, how far below the quote the trade may fill: a whole number of basis points from 1 to 9900 (0.01% to 99%), 100 unless given. The trade card sets it with its Slippage presets or a custom value. It prices the trade through Relay, or Jupiter for a trade within Solana, and answers `{ chain, fromChain, crossChain, cheapestNote, unroutable, details, steps }`, passing the router’s own `details` and `steps` through. Errors: `400`, `404`, `422` with the reason when no route was found, and `424` when a chain or the router could not be reached or took too long (with `retry: true` where trying again can help). Never a 5xx: a proxy in front may replace a 5xx body.

`/trade/solana-tx` takes `{ instructions, addressLookupTableAddresses?, payer }`, a swap step’s Solana instructions as the quote gives them, at most 24 instructions and 8 lookup tables, and answers `{ transaction, blockhash, lastValidBlockHeight }`: an unsigned versioned transaction. It does not inspect what the instructions do, so read them, or let your wallet simulate them, before you sign.

Part of the Pangea documentation: https://www.pangea.trade/app/docs.md
