> ## Documentation Index
> Fetch the complete documentation index at: https://docs.8bitedge.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Intelligence — Game endpoints reference

> Composite decision-support endpoints that blend demand with pricing into a 0–100 liquidity score: leaderboard, per-game profile, and lot/inventory batch scoring. Scope: intelligence.read.

The Intelligence API turns raw demand and pricing into ready-to-act answers. Where the [Demand & Intent](/api/demand-games) endpoints *report* first-party behaviour, Intelligence *blends categories* — demand signals combined with catalog pricing — to score how readily a title should move (`liquidity_score`). The endpoints on this page answer "across the catalog, what will actually move?", "for this specific title, how liquid is it and why?", and "here's my pile — score every title for me." To decide *how to sell* a copy (loose, CIB, or new), see [Intelligence: Conditions](/api/intelligence-conditions). All endpoints require the `intelligence.read` scope and a valid `Authorization: Bearer <token>` header.

<Warning>
  **Provenance caveat.** `liquidity_score` blends a *demand component* (first-party intent, reach, and watch demand) with a *price component* (catalog pricing). Supply is **not** directly observed, so liquidity is a **turnover proxy** — demand strength adjusted for price accessibility — **not** a measured sell-through rate. Treat it as a relative ranking signal, not a guaranteed sale rate.
</Warning>

## Common query parameters

The leaderboard and profile endpoints share the following query parameters.

<ParamField query="period" type="string" default="7d">
  The time window to aggregate over. One of `day`, `7d`, or `30d`.
</ParamField>

<ParamField query="date" type="string">
  Override the target window-end date. Defaults to the latest computed date for the selected period. Format: `YYYY-MM-DD`.
</ParamField>

<ParamField query="console_id" type="integer">
  Restrict results to games belonging to this console. Omit to score across all consoles. (Leaderboard only.)
</ParamField>

<ParamField query="limit" type="integer" default="25">
  Page size. Capped by your plan's `max_page_size`. (Leaderboard only.)
</ParamField>

## Derived fields

Several response fields are computed by blending demand and pricing rather than stored directly. Understanding how each is derived helps you interpret what it signals.

### `demand.index`

A `0.0`–`1.0` blend of three demand signals — intent (redirect clicks), reach (distinct users), and watch demand (watchlist alerts) — each normalised against the highest value in the current period and console scope. The most-demanded title in scope approaches `1.0`; every other title is scored relative to it.

### `price_accessibility`

A `0.0`–`1.0` score that is **higher for cheaper titles**, on the principle that lower-priced games turn over faster:

```
price_accessibility = 1 − (price_complete ÷ max_complete_price_in_scope)
```

A title with no catalog price falls back to a neutral `0.5`, so missing pricing never masquerades as high liquidity.

### `liquidity_score`

A single `0`–`100` index combining demand with price accessibility:

```
liquidity_score = 100 × (w_demand · demand.index + w_access · price_accessibility)
```

The two weights (`w_demand` and `w_access`) sum to 1 and are set in the API's serving configuration. A high score means a title is both in demand and priced to move.

### `momentum`

Whether interest is accelerating or fading, measured as the trailing 7-day daily pace against the 30-day baseline. This is the same calculation used across [Demand & Intent](/api/demand-games#momentum).

| Label     | Condition             |
| --------- | --------------------- |
| `rising`  | momentum 1.2 or above |
| `steady`  | between 0.8 and 1.2   |
| `cooling` | below 0.8             |

When a title has no 30-day baseline, `value` is `null` and `label` is `"unknown"`.

***

## GET /api/v1/intelligence

Returns a ranked **liquidity leaderboard** for the selected period. The result is anchored on titles with redirect demand, left-joining watch demand and catalog pricing. Use this to answer "across the catalog, what will actually move, and how should I weigh demand against price?"

```bash theme={null}
curl -s "https://api.8bitedge.com/api/v1/intelligence?period=7d" \
  -H "Authorization: Bearer $TOKEN" | jq
```

### Query parameters

In addition to the [common parameters](#common-query-parameters):

<ParamField query="sort" type="string" default="liquidity">
  Sort order for the leaderboard. One of:

  * `liquidity` — by `liquidity_score` descending (default)
  * `demand` — by `demand.index` descending (ignores price)
  * `value` — by complete-in-box price descending (highest-margin first); `liquidity_score` breaks ties
</ParamField>

### Response

Returns a paginated array of liquidity rows. The `meta` object includes the resolved `period`, `period_date`, and `sort`.

<ResponseField name="data" type="array">
  Array of liquidity rows, each representing one game ranked by the selected sort.

  <ResponseField name="rank" type="integer">
    The game's rank within the current period and sort.
  </ResponseField>

  <ResponseField name="game" type="object">
    Game identity fields.

    <ResponseField name="id" type="integer">Unique game ID.</ResponseField>
    <ResponseField name="name" type="string">Display name of the game.</ResponseField>
    <ResponseField name="slug" type="string">URL slug for the game.</ResponseField>
    <ResponseField name="console_id" type="integer">ID of the console this game belongs to.</ResponseField>
    <ResponseField name="console_name" type="string">Display name of the console.</ResponseField>
  </ResponseField>

  <ResponseField name="demand" type="object">
    Demand signals and the normalised blend used for scoring.

    <ResponseField name="redirects" type="integer">Purchase-intent clicks in the period.</ResponseField>
    <ResponseField name="distinct_users" type="integer">Unique users who clicked through.</ResponseField>
    <ResponseField name="watch_count" type="integer">Active watchlist alerts in the period.</ResponseField>
    <ResponseField name="index" type="float">The `0.0`–`1.0` blended demand index (see [Derived fields](#derived-fields)).</ResponseField>
  </ResponseField>

  <ResponseField name="momentum" type="object">
    Acceleration of interest relative to the 30-day baseline.

    <ResponseField name="value" type="float">Computed ratio. `null` when no 30-day baseline exists.</ResponseField>
    <ResponseField name="label" type="string">`rising`, `steady`, `cooling`, or `unknown`.</ResponseField>
  </ResponseField>

  <ResponseField name="pricing" type="object">
    Current market prices from the catalog.

    <ResponseField name="loose" type="string">Loose (cartridge/disc only) price as a decimal string.</ResponseField>
    <ResponseField name="complete" type="string">Complete-in-box price as a decimal string.</ResponseField>
    <ResponseField name="new" type="string">Sealed/new price as a decimal string.</ResponseField>
  </ResponseField>

  <ResponseField name="price_accessibility" type="float">
    The `0.0`–`1.0` price-accessibility score (higher = cheaper/faster-moving; see [Derived fields](#derived-fields)).
  </ResponseField>

  <ResponseField name="liquidity_score" type="integer">
    Composite `0`–`100` liquidity index blending demand and price accessibility.
  </ResponseField>
</ResponseField>

<ResponseField name="meta" type="object">
  <ResponseField name="period" type="string">The resolved period (`day`, `7d`, or `30d`).</ResponseField>
  <ResponseField name="period_date" type="string">The window-end date the data was computed for (YYYY-MM-DD).</ResponseField>
  <ResponseField name="sort" type="string">The active sort (`liquidity`, `demand`, or `value`).</ResponseField>
  <ResponseField name="pagination" type="object">Standard pagination metadata (see [Pagination](/concepts/pagination)).</ResponseField>
</ResponseField>

**Example response:**

```json theme={null}
{
  "data": [
    {
      "rank": 3,
      "game": {
        "id": 5337,
        "name": "Super Mario World",
        "slug": "super-mario-world",
        "console_id": 19,
        "console_name": "Nintendo SNES"
      },
      "demand": { "redirects": 412, "distinct_users": 287, "watch_count": 53, "index": 0.8123 },
      "momentum": { "value": 1.34, "label": "rising" },
      "pricing": { "loose": "28.00", "complete": "75.00", "new": "320.00" },
      "price_accessibility": 0.7656,
      "liquidity_score": 78
    }
  ],
  "meta": {
    "period": "7d",
    "period_date": "2026-06-19",
    "sort": "liquidity",
    "pagination": { "mode": "page", "page": 1, "per_page": 25, "total": 842, "last_page": 34 }
  },
  "links": { "next": "https://api.8bitedge.com/api/v1/intelligence?page=2", "prev": null }
}
```

***

## GET /api/v1/intelligence/{id}

Returns a **per-game intelligence profile** in the same row shape as the leaderboard. Unlike the leaderboard — which is anchored on titles that have redirect demand — this endpoint is anchored on the catalog, so any enabled game resolves even with zero demand. The score is normalised against the whole period population, so it stays comparable to the leaderboard. Use this to answer "for this specific title, how liquid is it, and why?"

```bash theme={null}
curl -s "https://api.8bitedge.com/api/v1/intelligence/5337?period=7d" \
  -H "Authorization: Bearer $TOKEN" | jq
```

### Path parameters

<ParamField path="id" type="integer" required>
  The numeric ID of the game. You can resolve IDs from the [Games catalog endpoints](/api/games).
</ParamField>

### Query parameters

<ParamField query="period" type="string" default="7d">
  The time window to aggregate over. One of `day`, `7d`, or `30d`.
</ParamField>

<ParamField query="date" type="string">
  Override the target window-end date. Defaults to the latest computed date. Format: `YYYY-MM-DD`.
</ParamField>

### Response

Returns a single liquidity row with the same fields as a leaderboard entry (`rank`, `game`, `demand`, `momentum`, `pricing`, `price_accessibility`, `liquidity_score`).

<Note>
  Returns `404 not_found` only when the `id` does not correspond to a real, enabled game in the catalog. A valid game with no demand still returns a row — with low demand metrics and a correspondingly low `liquidity_score`.
</Note>

<Tip>
  To decide which condition to list a copy in — loose, CIB, or new — use [`GET /api/v1/intelligence/{id}/conditions`](/api/intelligence-conditions), documented on the [Intelligence: Conditions](/api/intelligence-conditions) page.
</Tip>

***

## POST /api/v1/intelligence/batch

Score an entire **lot or inventory** in one request. Submit a list of game IDs and each is scored with the same liquidity logic as the leaderboard, against one shared period scope resolved once for the whole batch. Unknown IDs are returned as `{ "found": false }` rather than failing the batch. The API returns a `200` when every item succeeds and a `207` when there is a mix of outcomes — always inspect the `status` field of each item in `data`.

### Authentication

Send your API key as a bearer token. The key must carry the `intelligence.read` scope.

```
Authorization: Bearer <token>
```

### Query parameters

<ParamField query="period" type="string" default="7d">
  The period scope applied to every item in the batch. One of `day`, `7d`, or `30d`.
</ParamField>

<ParamField query="date" type="string">
  Override the target window-end date for the whole batch. Format: `YYYY-MM-DD`.
</ParamField>

### Request body

<ParamField body="requests" type="array" required>
  An array of request objects, each identifying a game by `game_id` (the key `id` is also accepted). The number of items must be at least 1 and no more than your plan's `max_batch_size`.

  | Plan       | Max batch size |
  | ---------- | -------------- |
  | Free       | 10             |
  | Starter    | 50             |
  | Pro        | 100            |
  | Enterprise | 250            |
</ParamField>

```json theme={null}
{
  "requests": [
    { "game_id": 5337 },
    { "game_id": 412 }
  ]
}
```

### Request example

```bash theme={null}
curl -s -X POST "https://api.8bitedge.com/api/v1/intelligence/batch?period=7d" \
  -H "Authorization: Bearer $BITEDGE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "requests": [ { "game_id": 5337 }, { "game_id": 412 } ] }'
```

### Response

**`200 OK`** — all items succeeded.\
**`207 Multi-Status`** — at least one item failed. Check each item's `status` field.

<ResponseField name="data" type="array">
  One entry per item submitted, in the same order as your `requests` array.

  <ResponseField name="data[].status" type="integer">
    HTTP status code for this individual item (`200` on success, `422` on per-item validation failure, etc.).
  </ResponseField>

  <ResponseField name="data[].data" type="object">
    Present when the item succeeded. Contains the game's liquidity row (same shape as a leaderboard entry). For an ID with no matching enabled game, the row is `{ "game_id": <id>, "found": false }`.
  </ResponseField>

  <ResponseField name="data[].error" type="object">
    Present when the item failed. Follows the standard error envelope with `code`, `message`, and optional `details`.
  </ResponseField>
</ResponseField>

<ResponseField name="meta.batch" type="object">
  Aggregate counts for the batch.

  <ResponseField name="meta.batch.total" type="integer">Total number of items submitted.</ResponseField>
  <ResponseField name="meta.batch.succeeded" type="integer">Number of items that returned a `2xx` status.</ResponseField>
  <ResponseField name="meta.batch.failed" type="integer">Number of items that returned a non-`2xx` status.</ResponseField>
</ResponseField>

**Example response:**

```json theme={null}
{
  "data": [
    {
      "status": 200,
      "data": {
        "game": { "id": 5337, "name": "Super Mario World", "slug": "super-mario-world", "console_id": 19, "console_name": "Nintendo SNES" },
        "demand": { "redirects": 412, "distinct_users": 287, "watch_count": 53, "index": 0.8123 },
        "momentum": { "value": 1.34, "label": "rising" },
        "pricing": { "loose": "28.00", "complete": "75.00", "new": "320.00" },
        "price_accessibility": 0.7656,
        "liquidity_score": 78
      }
    },
    {
      "status": 200,
      "data": { "game_id": 999999, "found": false }
    }
  ],
  "meta": { "batch": { "total": 2, "succeeded": 2, "failed": 0 } }
}
```

### Idempotency

Add an `Idempotency-Key` header to make your batch request safely retryable. If a network error prevents you from receiving the response, resend the same key and identical payload — the original response is replayed verbatim and the `Idempotency-Replayed: true` header is set. Stored responses expire after 24 hours.

```bash theme={null}
curl -s -X POST "https://api.8bitedge.com/api/v1/intelligence/batch" \
  -H "Authorization: Bearer $BITEDGE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "requests": [ { "game_id": 5337 }, { "game_id": 412 } ] }'
```

<Warning>
  Reusing an `Idempotency-Key` with a **different** request body returns `422 idempotency_key_reuse`. Generate a fresh key for each logically distinct request.
</Warning>

### Usage metering

Each object in the `requests` array counts as **one usage unit** against your monthly quota. A batch of 50 items consumes 50 units, regardless of whether individual items succeed, fail, or resolve to `found: false`.

### Error reference

| Status | `error.code`          | When                                                                                           |
| ------ | --------------------- | ---------------------------------------------------------------------------------------------- |
| 422    | `validation_failed`   | `requests` is missing or empty                                                                 |
| 422    | `batch_too_large`     | Item count exceeds your plan's `max_batch_size`; `details` includes `max_items` and `received` |
| 401    | `unauthorized`        | API key is missing, invalid, revoked, or expired                                               |
| 403    | `insufficient_scope`  | Key does not carry the `intelligence.read` scope                                               |
| 429    | `rate_limit_exceeded` | Per-minute or per-day rate limit hit; check the `Retry-After` header                           |
| 402    | `quota_exceeded`      | Monthly quota exhausted (non-overage plans)                                                    |

**Batch too large — example error response:**

```json theme={null}
{
  "error": {
    "code": "batch_too_large",
    "message": "The batch exceeds the maximum allowed size for your plan.",
    "details": { "max_items": 50, "received": 75 }
  }
}
```
