# GET /v1/line-history

> Independent. Not affiliated with, endorsed by or sponsored by Novig.

Canonical: https://novigapi.com/docs/endpoints/line-history
Facts checked: 2026-11-12

GET /v1/line-history returns a market's best bids, depth and last price over time from our own snapshots, which Novig's public catalog does not keep. New points are at most about 10 seconds old on paid plans. Novig's price candles needed an account key, checked 12 Nov 2026, so this history is ours. (Source: [Novig API docs](https://docs.novig.com))

## What it returns

A time series per market. We store a point whenever an outcome's best bid, quantity, last price, status, volume or open interest changes. Each row is one outcome at one moment, oldest first; pair the two outcomes' bids to get the fair price at that moment. One call reads a window of at most 31 days (24 hours by default) and at most 5,000 points; `meta.window` says which window was read and `meta.truncated` whether the cap cut it short.

Novig's free CSVs give one row per market per day. This endpoint is the intraday layer: when a line moved, how far and how fast.

## Parameters

Query and path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| market_id | string | No | Market to read. Send this or `outcome_id`. |
| outcome_id | string | No | One outcome's history. |
| since | string (ISO 8601) | No | Only points at or after this time. Free reads only the last 7 days. |
| until | string (ISO 8601) | No | Only points before this time. |
| limit | integer | No | Rows per page, 1 to 1,000. Default 100. Free returns at most 100. |
| cursor | string | No | `meta.next_cursor` from the previous page. |


## Request

```bash
curl -s "https://novigapi.com/api/v1/line-history?market_id=01a1d00f-ec01-71c0-9776-0facc97e44a7&since=2026-11-12T17:00:00Z&limit=2" \
  -H "Authorization: Bearer nv_..."
```

## Response

Trimmed to one point per outcome: the real snapshot of Cooper Flagg 1.5 steals at 17:23:56 UTC on 12 Nov 2026 (Over bid 0.39, Under bid 0.57). A full response lists one row per outcome per change; the fair price at any point is (Over bid + (1 - Under bid)) / 2.

```json
{
  "data": [
    {
      "outcome_id": "01a1d00f-ec01-71c0-9776-0fb0230cbd18",
      "market_id": "01a1d00f-ec01-71c0-9776-0facc97e44a7",
      "bid": 0.39,
      "bid_qty": 18938,
      "last": 0.415,
      "status": "PENDING",
      "volume": 198265,
      "open_interest": 146324,
      "observed_at": "2026-11-12T17:23:56.000Z",
      "source_age_seconds": 6,
      "edge_cached": true
    },
    {
      "outcome_id": "01a1d00f-ec01-71c0-9776-0fc320d7d309",
      "market_id": "01a1d00f-ec01-71c0-9776-0facc97e44a7",
      "bid": 0.57,
      "bid_qty": 7500,
      "last": 0.585,
      "status": "PENDING",
      "volume": 198265,
      "open_interest": 146324,
      "observed_at": "2026-11-12T17:23:56.000Z",
      "source_age_seconds": 6,
      "edge_cached": true
    }
  ],
  "meta": {
    "observed_at": "2026-11-12T17:23:56.000Z",
    "source_age_seconds": 6,
    "edge_cached": true,
    "next_cursor": null,
    "limit": 2,
    "count": 2,
    "window": {
      "since": "2026-11-12T17:00:00.000Z",
      "until": "2026-11-12T17:24:02.000Z"
    },
    "truncated": false,
    "plan": "developer",
    "credits_charged": 5,
    "credits_remaining": 9874,
    "credit_policy": "credits_v1"
  }
}
```

## Fields

Response fields

| Field | Type | Description |
| --- | --- | --- |
| outcome_id | string | The outcome this point belongs to. |
| market_id | string | Novig market id. |
| bid | number or null | Best bid on this outcome at that moment. |
| bid_qty | integer or null | Contracts at that bid. |
| last | number or null | Last traded price on this outcome. |
| status | string or null | Outcome status at that moment, `PENDING` until graded. |
| volume, open_interest | integer or null | Market volume and open interest at that moment. |
| observed_at | string (ISO 8601) | When we observed this state. `source_age_seconds` and `edge_cached` as on every row. |
| meta.window | object | `since` and `until` of the window read, in UTC. |
| meta.truncated | boolean | True when the window held more than 5,000 points; read again from the last `observed_at`. |
| meta.next_cursor | string or null | Pass as `cursor` to get the next page. Null on the last page. |
| meta.limit, meta.count | integer | The page size used and the rows on this page. |
| meta.observed_at | string (ISO 8601) | When our collector read the oldest row in this answer from Novig's public catalog. Each row also carries its own `observed_at`. |
| meta.source_age_seconds | integer | Seconds between that read and our response. On paid plans this stays at about 10 or less. |
| meta.edge_cached | boolean | True when Novig's edge cache served any of the reads, so the source copy may itself be a few seconds old. |
| meta.plan, credits_charged, credits_remaining, credit_policy | string, integer | Your plan, what this call cost, the credits left this month and the credit rules version. |


## Credit cost

Weighted 5x: 5 credits per call per 100 rows requested (the `limit` you send, default 100, maximum 1,000; Free pages hold at most 100 rows). A default page costs 5 credits. A day of a busy market can be a few thousand points; use `since` and `until` to read only what you need. Errors and 304 Not Modified cost 0; the `X-Credits-Cost` header and `meta.credits_charged` state the price of every call.

## Python

```python
import os
import requests

KEY = os.environ["NOVIGAPI_API_KEY"]  # nv_...
HEADERS = {"Authorization": f"Bearer {KEY}"}

import pandas as pd

params = {"market_id": "01a1d00f-ec01-71c0-9776-0facc97e44a7", "since": "2026-11-12T00:00:00Z", "limit": 1000}
points = requests.get("https://novigapi.com/api/v1/line-history", params=params, headers=HEADERS, timeout=10).json()["data"]
df = pd.DataFrame(points)
df["observed_at"] = pd.to_datetime(df["observed_at"])
over = df[df["outcome_id"] == "01a1d00f-ec01-71c0-9776-0fb0230cbd18"]
print(over.set_index("observed_at")["bid"].resample("5min").last().dropna())
```

## JavaScript

```javascript
const KEY = process.env.NOVIGAPI_API_KEY; // nv_...
const headers = { Authorization: "Bearer " + KEY };

const res = await fetch("https://novigapi.com/api/v1/line-history?outcome_id=01a1d00f-ec01-71c0-9776-0fb0230cbd18&limit=1000", { headers });
const { data } = await res.json();
const first = data[0];
const last = data[data.length - 1];
console.log("bid moved " + ((last.bid - first.bid) * 100).toFixed(1) + " points since " + first.observed_at);
```

## Notes and edge cases

- The window, not the page size, bounds a call: `limit` and `cursor` page through the points of that window. For longer spans, call again with the next `since`.
- History starts when our collector first saw the market. For days before that, use [daily OHLC](https://novigapi.com/docs/endpoints/ohlc-daily) from Novig's CSVs, back to 4 Aug 2026.
- Points are observations of a polled source. A change shorter than the poll interval (about 5 to 15 seconds for active markets) can be missed.
- Novig voids resting orders at `GOLIVE`, so most markets show a gap or a jump at the start of the game.
- For line moves above a threshold, without reading the full series, subscribe to [webhooks](https://novigapi.com/docs/endpoints/webhooks).

## Sources

- [Novig API docs](https://docs.novig.com)
- [Novig docs: Exchange Data](https://docs.novig.com/public-data/overview.md)
- [Novig docs: Lifecycle channel](https://docs.novig.com/api/streaming/lifecycle.md)

---

Get a free API key: https://novigapi.com/sign-up . Docs: https://novigapi.com/docs . MCP: https://novigapi.com/api/mcp . Operated by Stunning Couches LLC. Independent. Not affiliated with, endorsed by or sponsored by Novig.
