> For the complete documentation index, see [llms.txt](https://docs-v4.nftx.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs-v4.nftx.io/gacha/data-and-api.md).

# Data & API

Read a gacha machine's data — the subgraph entities, the read-API endpoints, and how NFTX computes rarity and APR from on-chain facts.

Everything a gacha machine does is indexed and readable without running your own node. There are three layers, from raw to convenient:

1. **Contract read views** — ground truth, straight off-chain.
2. **The subgraph** — the on-chain events indexed into queryable `Gacha*` entities.
3. **The read API** — the `Gacha*` entities served as REST, with rarity and APR computed for you. This is the same public "SDK" the NFTX app itself uses, and what most integrations should build on.

{% hint style="info" %}
Gacha is **pre-mainnet**. The endpoints below are chain-scoped like the rest of the [API](/api-reference/api-reference.md), but today only **Ethereum Sepolia** (`/v1/11155111/gacha/...`) has a machine to return. They join the live API Reference once the indexer and API are deployed for gacha.
{% endhint %}

## The read API

Every route is scoped to a chain and needs no API key:

```
/v1/{chain}/gacha/...
```

| Endpoint                                              | Returns                                                                                        |
| ----------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `GET /v1/{chain}/gacha/machines`                      | Every machine on the chain, with computed rarity odds and APR                                  |
| `GET /v1/{chain}/gacha/machines/{machineId}`          | One machine, or `404` if it doesn't exist                                                      |
| `GET /v1/{chain}/gacha/machines/{machineId}/stock`    | The NFTs currently in the machine (its prize pool). `?owner=` filters to one depositor's stake |
| `GET /v1/{chain}/gacha/machines/{machineId}/spins`    | Spin history. `?spinner=` filters to one player                                                |
| `GET /v1/{chain}/gacha/machines/{machineId}/pulls`    | Completed pulls (won prizes). `?winner=` filters to one winner                                 |
| `GET /v1/{chain}/gacha/machines/{machineId}/activity` | A merged event feed: spins, deposits, withdrawals, and sell-backs                              |

A machine response carries the protocol economics (spin price, expected value, vig, protocol fee, unit cap, live units, totals), the merged presentation metadata, and two fields NFTX computes for you — `rarityOdds` and `apr`.

## How rarity is computed

Rarity is **not a protocol concept** — the contracts price assets, they don't rank them. NFTX derives a display rarity from the one thing that's objective: an item's value relative to the machine's floor.

The machine floor is the cheapest live bucket's price. Each item's tier is its value ratio to that floor:

| Tier      | Value vs machine floor |
| --------- | ---------------------- |
| Legendary | ≥ 5×                   |
| Epic      | ≥ 3×                   |
| Rare      | ≥ 2×                   |
| Uncommon  | ≥ 1.5×                 |
| Common    | < 1.5×                 |

`rarityOdds` then groups the machine's *draw weights* by tier and reports each tier's share of the draw as a percentage. Because draw weight is inverse to price (cheap drops more often), the odds concentrate on Common — which matches how a gacha actually plays: the floor items are the common pulls, the dear ones the rare ones.

{% hint style="info" %}
The tier bands are a tunable heuristic, not an on-chain fact. They're a presentation layer over the protocol's price-driven weights, chosen to read the way players expect rarity to — treat them as a display aid, not a guarantee.
{% endhint %}

## How APR is computed

The depositor APR answers a plain question: *for the value staked in this machine, how much fee revenue has it thrown off, annualised?*

```
TVL  = Σ_bucket  liveUnits × floorPrice          (value depositors have staked)
APR  = (totalRevenue · seconds_per_year / machine_age) / TVL × 100
```

`totalRevenue` is the post-protocol-fee revenue the machine has streamed to depositors (the vig they've collected); `machine_age` is now minus the machine's creation time. A brand-new machine, an empty one, or one that's earned nothing yet reports no APR rather than a misleading number.

{% hint style="warning" %}
APR is an **estimate from realised history**, not a promise. It's backward-looking — it annualises the fees a machine has *already* generated against its *current* staked value. Spin volume is what pays depositors, and it varies; past APR does not predict future yield.
{% endhint %}

## Machine metadata

The protocol identifies a machine by `machineId` and collection addresses only — it has no name, art, or theme. NFTX merges those from a small, version-controlled registry shipped with the read API, keyed `{chainId}-{machineId}`:

| Field         | Meaning                                       |
| ------------- | --------------------------------------------- |
| `name`        | Display name (falls back to `Machine #{id}`)  |
| `symbol`      | Short ticker-style label                      |
| `description` | One-line blurb                                |
| `image`       | Card / avatar art                             |
| `bannerImage` | Wide banner art                               |
| `accent`      | Theme accent (one of the NFTX accent palette) |

A machine with no entry serves its data all the same — it just renders with a generated name and no art. To register a machine's presentation, see [Run your own machine](/gacha/run-your-own-machine.md#making-it-show-up-in-the-nftx-app).

## The subgraph

Under the API, the indexer maps the contracts' events into these entities:

| Entity             | What it records                                                              |
| ------------------ | ---------------------------------------------------------------------------- |
| `GachaSystem`      | Per-deployment totals (machines, spins, revenue)                             |
| `GachaMachine`     | A machine: collections, economics, live units, lifetime totals               |
| `GachaBucket`      | A machine's per-collection custody: live units, last price, draw weight      |
| `GachaBucketToken` | An individual NFT in a bucket, and its status (in machine / won / withdrawn) |
| `GachaSpin`        | A spin request and its lifecycle state                                       |
| `GachaSnapshot`    | The prices and units frozen at a spin's request time                         |
| `GachaPrize`       | A won NFT — who won it, from which collection, and for what value            |
| `GachaWithdrawal`  | A depositor's withdrawal through request → mature → execute → expire         |

## Contract read views

When you want ground truth without the indexer, read straight off-chain. The essentials:

* [**NFTXGacha**](/contracts/gacha.md) — `quote` (live price + snapshot hash), `machinePricing`, `spinRequests`, `pendingRewards`, and the VRF config.
* [**NFTXGachaVault**](/contracts/gacha-vault.md) — `machineCount`, `machineCollections`, `machineActive`, `drawableUnits`, `liveUnitsBatch`, `snapshotInputs`, `bucketTokenIds`, `withdrawableUnits`, and `pendingDeliveryCount`.

Those two pages document every public function, input, and return value.
