# For integrators and AI agents

Pangea is a token launchpad. Each launch deploys its token as five contracts, a LayerZero OFT on Ethereum, Base, Robinhood Chain and BSC and a mint on Solana, and opens one liquidity pool per chain at the same US dollar price. This section is the reference for reading and using it from code.

These docs are also published as Markdown, generated from the same source as this page:

- Index for language models: `https://www.pangea.trade/llms.txt`
- Everything in one file: `https://www.pangea.trade/llms-full.txt`
- These docs as Markdown: `https://www.pangea.trade/app/docs.md`

Each section is also on its own, at `/app/docs/<section id>.md`. This section is `/app/docs/integrators.md`.

## The five chains

| Chain | Name in the API | Chain id | Endpoint id |
| --- | --- | --- | --- |
| Ethereum | ethereum | 1 | 30101 |
| Base | base | 8453 | 30184 |
| Robinhood Chain | robinhood | 4663 | 30416 |
| BSC | bsc | 56 | 30102 |
| Solana | solana | none | 30168 |

The endpoint id is LayerZero’s, and it is how the token names a chain. Solana has no EVM chain id.

## Units

- Every token has 9 decimals, on all five chains. An amount in base units is a whole number at 9 decimals: one token is 1,000,000,000 base units.
- A transfer between chains crosses at 6 decimals. It is rounded down to a multiple of 1,000 base units, and the odd base units stay in the sender’s wallet.
- Fees are in basis points. One basis point is 0.01%.
- The standard supply is 5 billion tokens, 1 billion in each chain’s liquidity pool at launch. On an EVM chain `totalSupply()` starts at that chain’s 1 billion and is a reported figure that moves no balance, so every chain shows a market cap on the same basis ([LayerZero routes](https://www.pangea.trade/app/docs#routes) says how it is reported); `launchTotal()` is the sum across the five chains, and `localSupply()` what is on that chain now. On Solana the mint’s supply is what is on Solana now: tokens bridged in are minted there and tokens bridged out are burned. [The market cap situation](https://www.pangea.trade/app/docs#market-cap) explains why terminals show different market caps.
- Times in the API are unix seconds unless a field says otherwise.

## Rules that surprise people

- Every launch is paid for by the person launching it, once, on the chain they pick, in that chain’s native asset. There are no free launches.
- Every launch opens at a market cap of 3,000 on each chain: $0.000003 a token, the same price on every chain. Nobody chooses the opening price.
- A token has five addresses, one per chain, all different, and every one of them ends in `6ea`: the last three hex digits on the EVM chains, the last three characters of the mint on Solana. Read the addresses from the API. Do not assume two chains share one.
- A transfer between chains costs 0.2% of the amount, kept by the token for the platform, plus LayerZero’s message fee in the source chain’s native asset. It is attested after 1 confirmation on its source chain and typically arrives in 4 to 16 seconds.
- Each launch sets its trading fee once, between 0.3% and 5%. No contract function or program instruction changes it afterwards.
- The first transfer on a Solana route nobody has used yet also pays a one-time setup fee for that route. Every later transfer on that route does not. Any wallet can pay it, a smart-contract wallet too, except a Safe: its transactions wait for its owners, so a Safe bridges once the route is set up. Pay it from your own wallet, as the bridge page does: a payment sent through another contract (a multicall or a router) is refunded to that contract, not to you, and one made by delegatecall is not seen at all.
- On the four EVM chains nothing can mint more of a token. On Solana the mint authority is the token's store in Pangea's deployment of LayerZero's OFT program, which mints exactly what was burned on another chain. Bridging burns on one chain exactly what it mints on another.
- Prices on the five chains are separate markets. They are held together by arbitrage, not by a mechanism, and can differ.

## What you can and cannot do from code

- **You can read** every launch’s pools, prices, reserves and addresses, its trades and volume, recent bridge transfers and its metadata, over the HTTP endpoints below.
- **You can trade** directly against the pools: Uniswap v4 on the EVM chains, Meteora DAMM v2 on Solana. The API gives each pool’s id and venue.
- **You can bridge** by calling the token itself, or price a transfer over HTTP and sign the transaction it returns.
- **You cannot launch through an API.** A launch needs a price snapshot signed by the platform’s signer, and the endpoint that prepares one accepts requests from the Pangea site only. Launches are made on the launch page.
- **There are no API keys and no accounts.** Every endpoint here is public. Where one is limited, the limit is per caller, by IP address.
- **Do not crawl the API.** Each read costs reads on five chains. Call an endpoint when you need its answer; `robots.txt` asks crawlers to stay out of `/api/`.

## HTTP endpoints

All are under `https://www.pangea.trade/api`. They take and return JSON and need no key. Over a limit the answer is `429` with a message saying how many seconds to wait. An error is `{ "error": "..." }`. A value the chains could not give is `null` rather than a guess, so check for it.

| Endpoint | What it returns | Limit per caller |
| --- | --- | --- |
| `GET /pools` | Every launch, with its pool on each chain: addresses, price, reserves, supply. | None. Every caller is served one shared reading: re-read as soon as a trade moves a pool while the live page is open, and at least every 60 seconds unless the deployment sets another interval. |
| `GET /history` | Trades, volume in US dollars and price candles. | 30 uncached reads in ten minutes. An answer is reused for 45 seconds. |
| `GET /bridge/activity` | Recent transfers between chains. | None. |
| `GET /token/meta` | A token’s own metadata document: description, image, links. | None. |
| `POST /bridge/quote` | A transfer between chains, priced, with the transaction to sign. | 120 in ten minutes and 15 in any one minute. |

> **Note:** Every public endpoint, including the ones not described here, is in [API reference →](https://www.pangea.trade/app/docs#api)

- Pools, GET: `https://www.pangea.trade/api/pools`

No parameters. The answer is `{ live, readAt, rates, blockers, launches }`. When nothing has launched, `live` is false and `launches` is empty. Each launch carries:

| Field | What it is |
| --- | --- |
| `slug`, `name`, `symbol` | The launch’s name in every other endpoint (`slug`), and its name and symbol. |
| `pools[]` | One entry per chain, including chains that could not be read. |
| `pools[].chain` | The chain’s name in the API. |
| `pools[].token` | The token’s address on that chain. This is where a token’s five addresses are published. |
| `pools[].poolId`, `pools[].venue` | The pool’s id and the venue it is on. |
| `pools[].price`, `pools[].priceUsd` | Quote asset per token, and the same in US dollars. `quoteSymbol` names the quote asset. |
| `pools[].reserves`, `pools[].tokenReserves` | What the pool holds: quote asset, and whole tokens. |
| `pools[].localSupply` | Whole tokens on that chain now. |
| `pools[].error` | Why that chain has no reading, when it has none. |
| `launchTotal`, `launchTotalRaw` | The token’s total supply in whole tokens, and in base units as a string. For a perChain launch, 1B on each chain it is on. |
| `supplyModel`, `capSupply` | `"perChain"` for a new launch (1B per chain · 5B across 5 chains), `"global"` for one before. Market cap is the global one, a price times `capSupply`, which is `launchTotal`: the whole supply across all five chains (5B for perChain). |
| `cheapest`, `spreadUsd` | The chain with the lowest US dollar price, and the gap between the highest and lowest price as a fraction. |
| `sold`, `burnt` | Whole tokens that have left the pools, and whole tokens sent to the dead address across chains. |
| `metadataURI` | The token’s metadata document, as the contract names it. |

- History, GET: `https://www.pangea.trade/api/history`

Query: `launch`, a slug, or leave it out for every launch; `hours`, a whole number from 1 to 168, 24 unless given. The answer is `{ readAt, hours, cursor, rates, totals, launches }`. An unknown slug is a `404`. Each launch carries `volumeUsd`, `trades`, `coverage`, `chains`, `candles` and `recent`.

- `coverage` runs from 0 to 1. Below 1 the figures describe part of the window you asked for, not all of it. Show it, or check it.
- `candles` are `{ t, o, h, l, c, v }` in US dollars, one per bucket that traded, where `t` is the bucket's start. A bucket with no trade is left out, not filled with the last price.
- `recent` is the last trades, newest first: `{ id, chain, timestamp, txHash, side, tokenAmount, quoteAmount, quoteSymbol, priceUsd, valueUsd }`, where `side` is `buy` or `sell`.
- A coin's whole history, a page at a time: add `trades=latest` (the newest page) or `trades=before:<next>` (the page after the one that gave `next`) with `launch`, and `limit` of 50, 100 or 200. The answer is `{ slug, readAt, trades, next }`, every chain newest first, the rows as in `recent`; `next` is null on the page that reached the first trade. The first page also carries `total`, every trade since the launch, and `complete`, whether every chain is recorded back to it.

- Bridge activity, GET: `https://www.pangea.trade/api/bridge/activity`

Query: `token`, a slug, optional; `hours`, 1 to 168, 24 unless given; `limit`, 1 to 100, 25 unless given. The answer is `{ recording, hours, since, uncovered, totals, cursor, transfers }`. A transfer is `{ id, guid, slug, from, to, at, amount, party, complete, tookSeconds }`.

- `recording` false means this deployment keeps no record, and the list is empty for that reason, not because nobody bridged. `reason` says why.
- `uncovered` lists the chains whose sends are not recorded. A transfer out of such a chain appears as an arrival with no send.
- `complete` false means one side is recorded: a transfer in flight, or one that failed. The feed does not guess which.

- Token metadata, GET: `https://www.pangea.trade/api/token/meta`

Query: `launch`, a slug, required. The answer is `{ uri, resolvable, name, symbol, description, image, website, twitter, telegram }`, or `{ uri, resolvable: false, reason }` when the document cannot be opened. Every field is the token author’s own claim. The name and symbol that cannot be edited are the contract’s, in the pools endpoint.

- Bridge quote, POST: `https://www.pangea.trade/api/bridge/quote`

The body you POST:

```json
{
  "slug": "<launch slug>",
  "from": "base",
  "to": "bsc",
  "amount": "1000000000000",
  "user": "0x<sender, and the recipient unless one is given>"
}
```

| Field | What it is |
| --- | --- |
| `slug` | The launch. |
| `from`, `to` | Chain names, as in the table of chains above. They must differ. |
| `amount` | Base units, as a decimal string. |
| `user` | The EVM address sending, and the recipient on an EVM chain unless one is given. |
| `solanaUser` | The Solana address, when Solana is the source or the destination. |
| `recipient` | Optional. Who receives, when it is not the sender. |

The answer is `{ symbol, from, to, amount, routes }`, where `routes` holds two routes: `canonical`, the token’s own LayerZero transfer, and `fast`, the same transfer with a fast order. A route that cannot be used says why in `unavailable`. It carries:

| Field | What it is |
| --- | --- |
| `id` | `canonical` or `fast`. The fast route’s own fields are in [API reference](https://www.pangea.trade/app/docs#api). |
| `amountOut` | What the recipient receives, in base units. |
| `nativeFee` | What it costs in the source chain’s native asset, in its smallest unit. Send it as the transaction’s value. |
| `tokenFee`, `platformFee` | Everything taken in the token, and the platform’s part of it, in base units. Both are the token’s fee. |
| `seconds` | The estimated time. |
| `call` | The transaction to sign: `{ to, data, value, chainId }`. Null when the transfer cannot be built as one contract call, as out of Solana. |
| `setupFee` | Present when this transfer opens a Solana route: the part of `nativeFee` that pays for it, once. |
| `unavailable` | Present when the route cannot be used, with the reason. |

## Bridging from code

On an EVM chain the token is a LayerZero OFT and you call it directly. Ask `quoteOFT` what a transfer debits and delivers, name the delivered amount as the minimum, ask `quoteSend` for the message fee, and send that fee as the transaction’s value. Leave `extraOptions` empty: the gas the destination needs is already enforced by the token.

On the token, on the chain the transfer leaves:

```solidity
struct SendParam {
    uint32 dstEid;       // the destination's endpoint id
    bytes32 to;          // the recipient, left-padded to 32 bytes
    uint256 amountLD;    // base units
    uint256 minAmountLD; // the least that may arrive
    bytes extraOptions;
    bytes composeMsg;
    bytes oftCmd;
}
struct MessagingFee { uint256 nativeFee; uint256 lzTokenFee; }
struct OFTReceipt { uint256 amountSentLD; uint256 amountReceivedLD; }

function quoteOFT(SendParam calldata _sendParam)
    external view returns (OFTLimit memory, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory);
function quoteSend(SendParam calldata _sendParam, bool _payInLzToken)
    external view returns (MessagingFee memory);
function send(SendParam calldata _sendParam, MessagingFee calldata _fee, address _refundAddress)
    external payable returns (MessagingReceipt memory, OFTReceipt memory);

event OFTSent(bytes32 indexed guid, uint32 dstEid, address indexed fromAddress, uint256 amountSentLD, uint256 amountReceivedLD);
event OFTReceived(bytes32 indexed guid, uint32 srcEid, address indexed toAddress, uint256 amountReceivedLD);

error AmountTooSmallToBridge(uint256 amount);
error SlippageExceeded(uint256 amountLD, uint256 minAmountLD);
```

| Read on the token | What it returns |
| --- | --- |
| `BRIDGE_FEE_BPS()` | The token’s bridge fee in basis points: 20. |
| `bridgeFeeTo()` | Where that fee goes on this chain. |
| `peers(uint32 eid)` | The token’s counterpart on another chain. Zero means there is no route to it. |
| `decimals()` | 9, on every chain. |
| `totalSupply()` | The reported supply: this chain’s 1B slice, or, for a launch from the current factories, the token’s supply on Solana as the chain’s SupplyReporter mirrors it, never below `localSupply()` or above `launchTotal()`. |
| `launchTotal()`, `launchSlice()` | The whole launch’s supply across every chain, and this chain’s slice of it. |
| `supplyReporter()` | The only address that may report this token’s supply. Launches made before reporting existed have no such function. |
| `localSupply()` | What is on this chain now. |
| `metadataURI()` | The token’s metadata document. |

On Solana the token is an account of LayerZero’s OFT program, `SNyKyiZYU4R54SF9sYLmjCaCUsa1sC6QouNAj3x3Zzf`, and a transfer out of Solana is an instruction to that program, not a contract call. Into Solana the recipient is the wallet that will own the tokens.

## Launches on chain

On each EVM chain the launch factory emits one event per launch. The current factories’ addresses are in [LayerZero routes](https://www.pangea.trade/app/docs#routes).

On each EVM chain’s launch factory:

```solidity
event Launched(
    bytes32 indexed launchId,
    address indexed token,
    address splitter,
    address launchOwner,
    address locker,
    uint128 liquidity,
    uint256 dust
);
```

## Addresses

- A token’s five addresses are in the pools endpoint, at `launches[].pools[].token`, and on the token’s page.
- The current launch factories, and each chain’s LayerZero endpoint, libraries, executor and verifiers, are in [LayerZero routes](https://www.pangea.trade/app/docs#routes).

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