# Market

Where the network stands on the curve, its price history and every step that moved it, and an exact spot quote for buying or selling MLX, worked out by the same code the ledger uses.

The curve sets MLX's price from how much has been bought: 10,000 MLX per $100 at genesis, halving at every doubling ($20M, then $30M, then $40M, then every $50M of purchases). Spot buys pay the curve price plus a premium and move it forward; sells get the curve price less a discount and move it back. The rules are on [Curve](/protocol/curve).

## GET /api/curve {#curve}

```endpoint try
GET /api/curve?limit=2
```

The network's position now, what each seat mines, a light price series for a chart, and the list of steps that moved the curve.

```bash tab=curl
curl "https://mlx.app/api/curve?kind=spot&period=7d&limit=10"
```

```js tab=JavaScript
const { now, series } = await (await fetch("https://mlx.app/api/curve")).json();
console.log(`$${now.price.toFixed(6)} per MLX, ${(now.progress * 100).toFixed(3)}% to halving ${now.epoch + 1}`);
// series: [{ t, price }, …] is ready for a chart
```

```python tab=Python
import requests

d = requests.get("https://mlx.app/api/curve", params={"kind": "spot", "period": "7d", "limit": 10}).json()
print(d["now"]["price"], "USD per MLX")
for s in d["steps"]["items"]:
    print(s["t"], s["kind"], s["buy"], s["sell"])
```

The parameters only filter and page `steps`; `now` and `series` are always the whole picture.

| Parameter | Type | Notes |
| --- | --- | --- |
| `kind` | `all`, `node` or `spot` | Steps of every kind (default), only seat purchases, or only spot buys and sells. |
| `period` | `1h`, `24h`, `7d`, `30d` or `all` | Only steps from that window. |
| `sort` | `new` or `old` | Newest first (default) or oldest first. |
| `offset` | integer | Steps to skip. Pass the previous page's `next`. |
| `limit` | integer | Page size. The route has a default and a maximum. |

```json title="Response"
{
  "at": 1793116789227,
  "now": {
    "position": 27.020000000000003,
    "price": 0.01000093648568847,
    "epoch": 0,
    "nextAt": 200000,
    "progress": 0.0001351,
    "usdToNext": 19997298,
    "priceNext": 0.02,
    "perUnit": { "now": 9999.063602003862, "next": 5000 },
    "seats": [
      { "tier": "S", "name": "Core", "price": 250, "perDay": 20, "perHour": 0.8333333333333334, "lockDays": 10 }
    ],
    "emitted": 0,
    "referralPaid": 0,
    "rewardsLeft": 3000000000,
    "curveTotal": 2885390081.777927,
    "nodes": 12,
    "since": 1792312766202
  },
  "series": [
    { "t": 1792312766202, "u": 0, "n": 0, "e": 0, "v": 0, "price": 0.01 },
    { "t": 1792510129015, "u": 3.75, "n": 1, "e": 37499.756316, "v": 0, "price": 0.010000129965940905 }
  ],
  "steps": {
    "total": 15,
    "matched": 15,
    "offset": 0,
    "items": [
      { "t": 1793102873526, "h": 389, "u": 27.020000000000003, "n": 12, "e": 0, "price": 0.01000093648568847, "du": 0.010000000000001563, "dn": 0, "de": 0, "buy": 1, "sell": 0, "kind": "spot" }
    ],
    "next": 1
  }
}
```

`now.seats`, `series` and `steps.items` are trimmed here. All figures on this endpoint are **numbers in whole MLX and dollars**, not base-unit strings.

### `now`

| Field | Type | Notes |
| --- | --- | --- |
| `position` | number | Seat units bought so far, through seats and spot buys (less spot sells). |
| `price` | number | Curve price at `position`, dollars per MLX. |
| `epoch` | integer | Halvings so far. |
| `nextAt` | number | Position of the next halving. |
| `progress` | number | How far through this epoch, as a fraction. |
| `usdToNext` | number | Dollars of purchases until the next halving. |
| `priceNext` | number | Curve price at the next halving. |
| `perUnit` | object | MLX that $100 buys at the curve price, now and after the next halving. Spot buys pay the premium on top. |
| `seats` | array | The seats you can buy, starters first: `tier`, `name`, `price` (dollars), `perDay` and `perHour` (the most it mines on a Mac of its class, MLX) and `lockDays` (how long mined MLX stays locked). Newest-chip editions aren't listed here; see the table on [Seats](/protocol/seats). |
| `emitted` | number | MLX paid to seats up front under the old model. |
| `referralPaid` | number | MLX paid as referral bonuses under the old model. |
| `rewardsLeft` | number or null | MLX in `rewards.mlx`, the old seat reserve: 0 since it moved to `treasury.mlx` on 29 Oct 2026. |
| `curveTotal` | number | All the MLX the curve could ever give out (the integral of the rate). |
| `nodes` | integer | Seats on the ledger. |
| `since` | integer | Time of the genesis block. |

### `series`

A light price history for a chart: genesis, then one point per block that moved the curve, thinned out evenly when there are many, with the first and last points always kept. Each point has `t` (time), `u` (position), `n` (seats), `e` (MLX paid to seats up front, cumulative), `v` (spot volume in dollars, cumulative) and `price` (the curve price at `u`).

### `steps`

Every recorded step, each compared with the one before it: `t`, `h` (block height), `u`, `n`, `e`, `price`, the changes `du`, `dn` and `de`, the spot dollars bought and sold in that step (`buy`, `sell`) and its `kind`: `node` when seats were added, `spot` when only the spot market moved, `other` otherwise. `steps.total` counts all steps, `matched` those that pass the filter, and `next` is the next `offset` or `null`.

## GET /api/market/quote {#quote}

```endpoint try
GET /api/market/quote?side=buy&amount=10000000
```

An exact quote for a spot buy or sell, as the ledger would fill it right now. Use `minOut` as the `minOut` of the `swap` you sign: the ledger refuses a fill below it. Not cached.

| Parameter | Type | Notes |
| --- | --- | --- |
| `side` | `buy` or `sell` | Required. `buy` spends a stablecoin for MLX; `sell` spends unlocked MLX for USDC. |
| `amount` | string | Required. What you put in, in base units, digits only (`10000000` is 10 USDC on a buy, 10 MLX on a sell). |
| `stable` | `USDC` or `USDT` | On a buy, the coin you pay with. Defaults to `USDC`; anything else is read as `USDC`. Sells always pay USDC. |
| `account` | string | Optional full wallet name. When it exists, the quote also checks its balance of what goes in (unlocked MLX on a sell) and says so in `error`. |

```json title="Response"
{
  "side": "buy",
  "tokenIn": "USDC",
  "tokenOut": "MLX",
  "amountIn": "10000000",
  "out": "799924949",
  "minOut": "795925324",
  "price": 0.012501172772675529,
  "position": 27.020000000000003,
  "premium": 0.25,
  "error": null,
  "liquidity": { "usd": "1677000000", "mlx": "1499995840385794" },
  "at": 1793116792558
}
```

| Field | Type | Notes |
| --- | --- | --- |
| `side`, `tokenIn`, `tokenOut` | string | What the quote is for. |
| `amountIn` | string | The amount you sent, base units. |
| `out` | string | What you would get, base units. |
| `minOut` | string | `out` less the slippage allowance the MLX Wallet uses. Sign this as the swap's `minOut`. |
| `price` | number | Dollars per MLX for this fill, premium or discount included. A bigger order moves further along the curve, so it gets a slightly different price. |
| `position` | number | The curve position the quote was taken at. |
| `premium` | number | The buy premium (on a buy) or the sell discount (on a sell) that applies now, as a fraction. |
| `error` | string or null | Why the ledger would refuse this swap, in its own words: below the smallest buy or sale, not enough balance (only with `account`), too small to give anything, more than the treasury can fill, or more than sell liquidity can pay. `null` when it would go through. |
| `liquidity` | object | `treasury.mlx`'s USDC (`usd`, what sells are paid from) and MLX (`mlx`, what buys are filled from), base units. |
| `at` | integer | When the quote was made, ms. |

A quote with an `error` still answers 200 with the figures filled in, so an app can show the reason next to the numbers.

```json title="A sell that the balance doesn't cover (GET /api/market/quote?side=sell&amount=1000000&account=luca.mlx)"
{
  "side": "sell",
  "tokenIn": "MLX",
  "tokenOut": "USDC",
  "amountIn": "1000000",
  "out": "8000",
  "minOut": "7960",
  "price": 0.008000749332381929,
  "position": 27.020000000000003,
  "premium": 0.2,
  "error": "Only unlocked MLX can be sold. You don't have that much unlocked MLX.",
  "liquidity": { "usd": "1677000000", "mlx": "1499995840385794" },
  "at": 1793116903498
}
```

The curve moves with every buy, sell and seat, so a quote is good only until the next block. To buy or sell, sign a `swap` with the quote's `minOut` and submit it: see [Transaction types](/transactions/types) and [Submitting](/transactions/submitting).

## Errors

| Status | When |
| --- | --- |
| 400 | `/api/market/quote`: `"side must be buy or sell"`, or `"amount must be whole 6-decimal units"` (missing, negative, with a decimal point or too long). |
| 500 | The ledger couldn't be read. |

`/api/curve` never answers 400: unknown filter values fall back to their defaults.
