# Read API

**Building a trading bot?** Follow the [buy/sell bot guide](/docs/bot-trading/) for exact approvals, live quotes and transactions through the Rearctor pool before and after graduation.

The Rearctor API serves indexed token information at **`https://api.rearctor.io/api`**. It reads the saved index rather than making a blockchain request for each visitor. It does not submit transactions, hold signing keys, or authorize spending.

[Download the OpenAPI 3.1 specification](/docs/openapi.json). For data coverage and freshness, see [How indexing works](/docs/indexing/).

## Requests and responses

Use `GET` to read JSON or `HEAD` to receive the corresponding headers without a response body. No API key or cookies are required. JSON responses use `Cache-Control: no-store`. The production browser CORS policy permits `https://rearctor.io`; public access does not imply that arbitrary browser origins are allowed. Server-side clients and command-line tools are not restricted by browser CORS. The public proxy handles `OPTIONS` preflight requests separately.

```sh
curl --fail --show-error 'https://api.rearctor.io/api/tokens?q=helix&limit=10'
```

Unknown query parameters and repeated parameters are rejected. Integer query parameters use non-negative decimal notation without signs, fractions or leading zeroes, except the value `0` itself. Request URLs longer than 4,096 characters are rejected by the application.

Amounts are unsigned **decimal strings in base units**, not floating-point JSON numbers: USDC uses six decimals and launch tokens use eighteen. For example, `"1500000"` USDC units means 1.5 USDC. Block numbers, token creation times and on-chain execution counters are also decimal strings. Pagination counts, token IDs, log indexes, fee basis points and displayed prices are JSON numbers. Event timestamps are Unix **seconds**; `status.updatedAt` and history `fetchedAt` are Unix **milliseconds**. `price` is an approximate USDC-per-token display value, never an executable quote.

Names, symbols, descriptions, images and social links are creator-supplied metadata. Treat them as untrusted content. An address or a matching name alone does not grant official-token status.

## Snapshot status

Successful data responses include `status`. Most application errors also include it when snapshot status has already been read.

| Field | Meaning |
| --- | --- |
| `mode` | `demo` or `live`. Demo values are illustrative, not blockchain activity. |
| `state` | `starting`, `initializing`, `syncing`, `ready`, `stale` or `error`. |
| `chainId` | Configured chain ID, or `null` before configuration is available. |
| `factory`, `treasuryAddress` | Configured contract addresses, or `null`. |
| `indexedBlock` | Last committed confirmed block, as a string; `null` in demo or before the first checkpoint. |
| `headBlock` | Most recently observed chain head, as a string, or `null`. |
| `updatedAt` | Time of the last committed snapshot in milliseconds, or `null`. |
| `error` | A sanitized availability message, or `null`; no provider credentials or internal paths are returned. |

A readable snapshot can be returned with HTTP 200 while `state` is `syncing` or `stale`. A live `ready` snapshot older than two minutes is exposed as `stale`. Age measures the last committed snapshot, not a separate worker heartbeat. Check both state and time; do not equate HTTP 200 with current chain state.

## Routes

All paths below are relative to the API base. Each also supports `HEAD`.

### `GET /health`

Returns `{ok, ready, status}`. HTTP 200 and `ready: true` mean a usable saved snapshot exists, including demo or stale data. HTTP 503 and `ready: false` mean no usable snapshot exists. This 503 response is a health response, not the normal error envelope. No query parameters.

### `GET /tokens`

Searches and paginates the entire indexed catalogue. It covers the configured Rearctor factory, not every token on Arc.

| Parameter | Default | Accepted values |
| --- | --- | --- |
| `q` | Empty | Up to 200 characters after trimming; embedded control characters are rejected. Matches name, symbol, token address or canonical pool address by substring. ASCII matching is case-insensitive; `%`, `_` and backslash are literal search characters. |
| `limit` | `24` | Integer 1–100. |
| `offset` | `0` | Integer 0–1,000,000,000. |
| `filter` | `all` | `all`, `charging` (not graduated), `ignited` (graduated). |
| `sort` | `newest` | `newest` by creation time; `volume` by the canonical pool's volume counter; `marketcap` by approximate price × current total supply. Descending order, then token ID descending. |

Envelope: `{items, total, limit, offset, status, config, summary, officialUpcoming}`.

`total` counts all matches before pagination. `summary` always covers the whole indexed catalogue, independent of search or filtering: `{count, volume, approaching, graduated}`. `approaching` counts ungraduated tokens with reserves at least 75% of their threshold. `config` can contain `count`, `quote`, `minimumSeed`, `threshold` and `owner`; fields may be absent during early deployment backfill.

`officialUpcoming` advertises the upcoming Rearctor token when the search matches its name, including an empty search. It is separate from `items` and is not counted in `total`. No placeholder token contract is invented. The filter is a market-state filter, not an identity or trust filter.

Paginate using `offset + items.length` while that value is below `total`. Separate requests can observe different snapshots, so a changing catalogue may shift offset-based pages. There is no snapshot-pinning or cursor parameter.

### `GET /tokens/{identifier}`

Returns `{launch, metric, graduationTransfer, status}`. The identifier is a zero-based factory launch ID or an exact token/pool address. IDs cannot have leading zeroes. A symbol, token name, vault address or creator address is not a supported identifier. `/tokens/rearctor` is not an API alias; use `/official` to resolve the official token.

The launch includes identity and metadata, immutable fee settings, price, supply, curve/migration amounts and graduation state. Before graduation, `tokens`/`reserve` are the pool's curve reserves. After graduation, they are the recorded migrated token/USDC amounts, not continuously updated V4 balances. `virtualTokens`/`virtualReserve` remain curve-state fields.

`metric` may be `null`; otherwise it contains the same counter/budget fields as an analytics row, without its nested `launch`.

`graduationTransfer` is always present and is `null` when no confirmed manual-graduation transfer event has been indexed, including preview records. A record contains:

| Field | Meaning |
| --- | --- |
| `recipient` | Fixed dead address receiving the accounted token remainder |
| `amount` | Transferred token base units, as a decimal string; 18 decimals |
| `transactionHash` | Transaction emitting the pool’s `GraduationRemainderSentToDead` event |
| `blockNumber` | Confirmed event block, as a decimal string |
| `logIndex` | Event index within that block, as an integer |
| `timestamp` | Block time in Unix seconds |
| `totalSupplyReduced` | Always `false`; this is a transfer, not an ERC-20 burn |

This record is separate from project/protocol buyback counters and market-execution history. Its amount covers only the migration transfer, not all transfers ever made to the dead address. `launch.supply` remains the actual ERC-20 total supply; do not subtract this amount from that field.

### `GET /tokens/{identifier}/history`

Returns `{history, status}` with **at most the latest 5,000 priced executions**, ordered oldest to newest within that returned window. It accepts no query parameters; older-history pagination and custom time windows are not exposed by this route.

`history` contains `pool`, `sample`, coverage blocks/times, optional `snapshotHash`, `fetchedAt`, `executions`, `omittedZeroAmountSwaps`, `totalExecutions` and `truncated`. `totalExecutions` is the full indexed priced-execution count; `truncated` signals omitted earlier records. When truncated, the displayed coverage starts at the first returned event. `omittedZeroAmountSwaps` counts indexed zero-amount V4 swaps that cannot establish a price.

Each execution has `id`, `blockNumber`, `logIndex`, `timestamp`, `side`, `source`, `actorKind`, `quoteAmount`, `tokenAmount` and `price`; live records also have `transactionHash` and `actor`. `source` is `curve` or `v4`. V4 `actorKind: "pool-caller"` may identify a router, not an end-user wallet. Sample records have `actorKind: "sample"` and no invented transaction hash. Distinct logs in one transaction remain distinct executions.

### `GET /tokens/{identifier}/burns`

Returns `{burns, total, limit, offset, truncated, status}` for that project's vault buybacks. Parameters: `limit` 1–500 (default 100), `offset` 0–1,000,000,000 (default 0). Events are newest first by block and log index. `truncated` means more events remain after this page; use `offset + burns.length` to continue.

Each burn includes `id`, `timestamp`, `spent` (USDC units), `burned` (this token's units), `block`, `index` and the nested `launch`. Live records also contain `hash`. These records cover vault buybacks; direct holder burns reduce token supply but are not listed as project buybacks.

### `GET /tokens/{identifier}/holders`

Returns `{concentration, status}`. No query parameters. `concentration` is `null` in demo mode or when no summary exists; it does not mean zero holders.

A live summary has `holders`, `top`, `topFive`, `creator`, `feeWallet`, `supply` and `blockNumber`. `top` contains up to five `[address, balance]` tuples, with decimal-string balances. Pool, fee vault, V4 manager and the fixed dead address are excluded from holder count and ranking. Creator and creator-fee-wallet balances are returned separately and may also appear in the ranking. Percentages should divide by current **total supply**, which still includes excluded infrastructure and dead-address balances. Multiple addresses can belong to one person.

This route is a concentration summary, not a complete holder list or a wallet portfolio endpoint. Connected-wallet holdings, allowances and personal claimable rewards are not exposed by this API and remain fresh chain reads in the application.

### `GET /protocol-fees`

Returns `{rows, total, limit, offset, status}`. Each row contains its `launch` and four exact counters: `protocolQuoteAccrued`, `protocolQuoteClaimed`, `protocolTokenAccrued`, `protocolTokenClaimed`. The difference for each asset is its uncollected protocol entitlement. Uncollected V4 position fees are excluded until moved into the vault.

Parameters: literal `q` search over token name, symbol, token/pool address; `pending=yes|no` (default `yes`); `limit` 1–50 (default 10); `offset` 0–1,000,000,000. Results use descending launch ID. Search and filtering cover the whole catalogue. The collection interface displays ten sources per page and signs only explicitly selected vaults.

### `GET /analytics`

Returns `{rows, burns, total, truncated, scope, burnScope, status}`. No query parameters.

`rows` contains up to 10,000 fee-counter snapshots ordered by launch ID. Each row has a nested `launch` and:

| Fields | Units / meaning |
| --- | --- |
| `spent`, `quoteBudget` | USDC spent by project buybacks / available project buyback budget. |
| `burned`, `tokenBudget` | Project tokens burned / available token-denominated buyback budget. |
| `executions`, `supply` | Buyback execution count / current token total supply. |
| `protocolQuoteAccrued`, `protocolQuoteClaimed` | Protocol USDC allocated / paid by the vault. |
| `protocolTokenAccrued`, `protocolTokenClaimed` | Protocol token units allocated / paid by the vault. |
| `liquidityQuoteBudget`, `liquidityTokenBudget` | Available reinvestment budgets, separately by asset. |

Token amounts from different launches must not be added as if they were one asset. Uncollected V4 fees are not already-realized vault budgets.

`total` is the full catalogue count; top-level `truncated` indicates fewer returned rows than that count. `scope` exposes `{returned, total, metricsTotal, truncated, complete}`: its own `truncated` compares returned rows with stored metrics, while `complete` checks coverage of the whole catalogue. Inspect these fields before claiming complete totals. The route has no row-pagination parameter.

`burns` contains the latest 100 project-buyback events across all launches, newest first. `burnScope: {returned, total, truncated}` describes event coverage. Use each token's `/burns` route for additional project history.

### `GET /treasury`

Returns `{snapshot, burns, total, limit, offset, truncated, status}`. Uses the same burn pagination parameters as a token's `/burns` route. `snapshot` is `null` when the dedicated treasury is not configured, including the demo fixture; missing data must not be rendered as collected revenue.

A treasury snapshot contains `owner`, `pool`, `token`, `available`, `received`, `converted`, `spent`, `burned`, `executions`, `operations` and `block`. USDC fields respectively track recorded available protocol funds, receipts, conversion proceeds, Rearctor-buyback spending and operations withdrawals. `burned` uses Rearctor token units. These values describe the last indexed block, not a spending authorization.

`burns` here are **protocol-funded Rearctor buybacks**, separate from project-vault burns. Treasury burn records do not contain a nested `launch`. Resolve the verified target through `/official` when linking to its token page.

### `GET /official`

Returns one of `{state: "verified", launch, status}`, `{state: "upcoming", message, status}` or `{state: "unavailable", message, status}`. No query parameters. Verification uses the configured treasury/factory binding and the first canonical launch, not a name search. `upcoming` means launch and verification are pending; it is not a live token address.

## Errors and limits

The normal application error envelope is `{error: {code, message}, status?}`. Raw RPC errors and configuration secrets are not exposed.

| HTTP | Code | Meaning |
| --- | --- | --- |
| 400 | `INVALID_REQUEST` | Invalid identifier/query, unknown or repeated parameter. |
| 404 | `NOT_FOUND` | Unknown API route. |
| 404 | `TOKEN_NOT_FOUND` | No matching launch in the current indexed snapshot. |
| 405 | `METHOD_NOT_ALLOWED` | Backend methods other than GET/HEAD; includes `Allow: GET, HEAD`. |
| 414 | `URI_TOO_LONG` | Application URL-length limit exceeded. |
| 503 | `INDEX_NOT_READY` | No usable snapshot yet; includes `Retry-After: 5`. |
| 503 | `HISTORY_UNAVAILABLE` | A known token's indexed history is unavailable. |
| 503 | `INDEX_UNAVAILABLE` | An internal indexed-data read failed. |

The current public proxy allows 30 requests/second per visitor with a burst of 60 and returns HTTP 429 when that budget is exceeded. Back off on 429/503; routine polling faster than the index update interval does not make chain data fresher. Proxy or Cloudflare errors can be non-JSON and do not necessarily use the application error envelope.

## Clearly labeled sample

This is an **illustrative demo-mode** response, not proof of live deployment or current service health:

```json
{
  "state": "upcoming",
  "message": "The official Rearc token has not been launched and verified yet.",
  "status": {
    "mode": "demo",
    "state": "ready",
    "chainId": 5042,
    "factory": null,
    "treasuryAddress": null,
    "indexedBlock": null,
    "headBlock": null,
    "updatedAt": 1789560000000,
    "error": null
  }
}
```

Clients should inspect the actual returned mode and status every time. The [OpenAPI document](/docs/openapi.json) includes additional labeled examples and exact response schemas.

## Network-specific API bases

The same read-only routes are available on two isolated indexes: `https://api.rearctor.io/api` for Arc Mainnet and `https://api.rearctor.io/api/testnet` for Arc Testnet. Always validate `status.chainId`, factory, treasury and mode against the intended deployment. Numeric token IDs and demo fixtures are not cross-network identities. No endpoint changes the active network of another visitor or submits a transaction.

## Token image uploads

A separate website upload endpoint is available at `POST https://rearctor.io/api/images`. It accepts a raw JPG, PNG or WebP body (not multipart), with the matching `Content-Type`, up to 2 MiB and 20 megapixels. Requests require the website Origin `https://rearctor.io`; this check is not wallet authentication. Uploads are rate-limited separately. The service re-encodes static images as WebP, strips embedded metadata, preserves aspect ratio and caps dimensions at 1024 × 1024.

Success: HTTP 201 with `{url, bytes, originalBytes}`. The returned URL is public and persistent. `GET` and `HEAD` at that image URL return `image/webp` with immutable caching. Upload errors use `{error: "message"}` with HTTP 400 for invalid images, 403 for invalid origin, 413 for size, 415 for unsupported content type, 429 for rate/capacity limits, or 507 when storage is full. Proxy errors may be non-JSON. This endpoint does not sign or submit transactions and is separate from the read-only indexed market routes above.
