# DepthFeed API integration guide

Updated September 19, 2026. This guide covers the current integration contract for discovery, cross-venue sports matching and historical books. Examples use `https://api.depthfeed.com` and a key supplied through `X-API-Key` or `Authorization: Bearer`. A successful status code does not establish data completeness.

## Discover markets and choose the correct identifier

| Surface | Discovery | Identifier for book history |
|---|---|---|
| Sports, both venues | `/v3/sports/markets` | An entry in `tokens[]` |
| Polymarket, any category | `/v3/polymarket/markets` | `asset_id` / outcome token |
| Polymarket crypto market | `/v3/{coin}/markets` | `market_id` for the market-level endpoint |
| Kalshi | `/v3/kalshi/markets` | Market ticker |
| Polymarket US, any category | `/v3/polymarket-us/markets` | Market slug |
| Limitless | `/v3/limitless/markets` | Market slug |
| PredictFun | `/v3/predictfun/markets` | Market ID |

Both `/v3/kalshi/markets` and `/v3/polymarket-us/markets` accept `category` and `exclude_category` as comma-separated lists of the venue's own labels, matched case-insensitively and combinable. On Kalshi the default listing is limited to markets with captured depth; `include_uncaptured=true` returns the venue's full catalogue, and each row's `depth_captured` states whether a book series exists behind it. Both listings take `updated_since`; on Polymarket US it selects rows whose content changed since that time and each row carries `updated_at`.

Sports market lookup accepts `/v3/sports/markets/{condition_id}` and also resolves an outcome token to its parent market. Always use `tokens[]` for `/v3/sports/books/{asset_id}/history`. A grouped Kalshi moneyline has an event identifier as its `condition_id` and separate market tickers as its tokens; these are not interchangeable.

`outcomes[i]` and `tokens[i]` align within one market. Neither label nor index is a cross-venue outcome identity. Existing outcome labels and `kind` values remain venue-native; common spellings do not establish equivalent contracts.

## Sports identity and moneyline comparisons

The following fields answer different questions:

| Field | Meaning |
|---|---|
| `game_slug` | Venue-specific handle used by the game routes |
| `cross_venue_key` | Same supported fixture or future subject; not equivalent payout terms |
| `contract_mapping.candidate_key` | Same supported fixture, participants and moneyline category; suitable for investigating candidates |
| `contract_mapping.outcomes[].participant_key` | Canonical participant corresponding to the supplied token |
| `cross_venue_market_key` | Confirmed contract key; null unless the mapping is `matched` |
| `contract_mapping.outcomes[].cross_venue_outcome_key` | Confirmed outcome key; null without confirmed contract equivalence |

The initial moneyline scope covers NFL, NBA, MLB, NHL, WNBA, CFB and CBB. Other leagues, futures, spreads, totals and props do not receive confirmed contract keys in this release. Some supported markets still need evidence or identity review. Do not interpret a null key as an error or replace it with the candidate key.

Release coverage on September 19: candidate alignment and rule-difference diagnostics are live; no complete equivalence profiles have been approved yet. Confirmed contract keys therefore remain null. Evidence refresh and review coverage are separate from endpoint availability.

`contract_mapping` is included on the market listing, single-market lookup, fixture-market listing and markets embedded in game responses. No separate contract-equivalence endpoint is required. Existing fields retain their meaning.

| `status` | Client behavior |
|---|---|
| `matched` | A counterpart has the same reviewed terms. Join by the confirmed market and outcome keys; inspect the counterpart list. |
| `unmatched` | A known difference, unsupported scope or absent counterpart prevents a confirmed join. Read `reason_codes`. |
| `needs_review` | Evidence, participant identity or mapping availability is insufficient. Do not treat it as an equivalent contract. |

Comparisons cover period, overtime, ties, postponement, cancellation, result source and result finality. `terms` can contain nulls: diagnostic extraction is not proof of a complete rule review. A confirmed key requires `terms_verified: true`. `evidence_hash`, `evidence_sources`, `evidence_checked_ms` and `evidence_valid_until_ms`, when available, identify the evidence and its freshness. Expired evidence or changed market inputs cannot keep a confirmed key. Coverage will vary; the existence of these fields does not promise a confirmed counterpart for every moneyline.

`comparisons[]` identifies each candidate counterpart with its own status and reasons. A market can have one matched counterpart and another unmatched one. Never assume every entry shares the row's overall status.

The reported Rams–49ers pair illustrates a valid exclusion. Both rows share fixture `nfl-lar-sf-2026-09-10`; Kalshi's “Los Angeles R” and Polymarket's “Rams” align to `nfl:lar`, while “San Francisco” and “49ers” align to `nfl:sf`. Their postponement clauses differ: one specifies a 48-hour start window and a fallback settlement, while the other waits for completion. The comparison therefore reports `unmatched` and `different_postponement`, with no confirmed contract key.

Full settlement-rule text is not returned as part of the sports market response. The source links and structured evidence fields support review; unknown conditions are not assumed to match.

### Fixture and market endpoints

```
GET /v3/sports/markets
GET /v3/sports/markets/{condition_id}
GET /v3/sports/games/{game_slug}
GET /v3/sports/games/{game_slug}/markets
```

The fixture-market endpoint is paginated. Follow its cursor to retrieve the complete collection. There is no `cross_venue_key` listing filter; collect candidate groups in your own store. Fixture dates may use the local game date, while `game_start` is a UTC instant. Do not reconstruct one from the other. Doubleheaders and future seasons require their full published identities.

## Incremental updates without full reloads

Sports listings support `updated_since` as epoch milliseconds, ISO-8601 or a date. `updated_at` and `updated_ms` are catalogue publication times, not settlement times. Identity, kickoff and contract-mapping corrections publish market updates. Evidence renewals are also published so consumers can refresh validity timestamps.

1. Save the poll-start time and your previous checkpoint.
2. Keep `updated_since` and all filters fixed while following every `next_cursor`.
3. Upsert complete market records by `condition_id`, including nulls that revoke old mappings.
4. Include resolved markets. Do not use `resolved=false` for steady-state correction polling.
5. After every page succeeds, advance the checkpoint from the poll-start time with an overlap that covers your delivery delay and clock skew. Do not advance to the largest update timestamp observed during a changing traversal.
6. Retry a failed traversal from the previous checkpoint. Reprocessing the overlap must be idempotent.

`updated_since` updates market metadata. It does not deliver corrected historical book rows or modify a client's warehouse. Retrieve affected historical windows again when historical captures need refreshing. Mapping keys can be revoked or replaced; retain the market's stable identifier as the upsert key.

## Pagination and page caps

Catalogue and book-history caps depend on the plan and route. The current standard caps are:

| Plan | Catalogue rows | Book-history rows |
|---|---:|---:|
| Explorer | 200 | 500 |
| Quant | 400 | 750 |
| Research | 500 | 1,000 |
| Desk | 5,000 | 5,000 |

These are not universal caps for trades, ladders, reference datasets or every other route. Endpoint-specific caps still apply. Read the returned pagination envelope and the account information from `/v3/whoami`.

Cursors are opaque. Reuse them only on the same endpoint and with the same identity, time range, resolution and filters. Do not construct a cursor from the last timestamp. Several distinct captures can share one exchange timestamp; current raw snapshot cursors preserve those records across page boundaries. Old timestamp cursors remain accepted, but new integrations must use the cursor returned by the service.

Continue while `has_more` is true using `next_cursor`, including after an empty page. If the service repeats a cursor or supplies no cursor while claiming more, stop and retry from the saved checkpoint rather than silently skipping data.

`pagination.count` describes the returned page. `include_count=true` requests a total for the filtered result; it is not proof of venue-wide capture completeness. Market-level crypto snapshots coalesce captures at the same exchange timestamp and count those timestamp groups. The raw Polymarket token endpoint can return multiple captures at that timestamp.

## Captures, sampled books and ticks

An interval is a sampling grid, not a guarantee that the source was recorded at that frequency. `interval=1s` does not create one genuine capture every second. Without forward fill, a bucket with no eligible capture can be absent. With `fill=ffill`, the last known book is carried forward where a seed exists; inspect `filled` and `as_of_ts` to distinguish carried observations from captures.

Sports history returns newest first. Crypto and venue snapshot routes return oldest first. Preserve the returned cursor and use timestamps when combining streams.

Use the corresponding ticks routes when individual captured updates are needed. A sampled book endpoint and an event stream have different semantics. Missing observations cannot be reconstructed from settlement metadata.

Sparse results can reflect capture cadence, source availability or missing history; row count alone does not establish why. A completed page traversal or `resolution.complete` is not a guarantee that every venue event was captured. Compare timestamps and coverage information for the relevant window.

## Prices, volume and successful-but-partial responses

Inspect `meta.partial` and accompanying metadata before storing a response as complete. Price enrichment can be temporarily unavailable even when the request returns HTTP 200. A null price must not be converted to zero. Retry transiently partial responses while preserving your checkpoint.

Sports `volume` is USD on Polymarket and contracts on Kalshi. Use `volume_unit`; do not sum unlike units. `volume_usd` provides the available USD measure, with `volume_usd_complete` and `volume_usd_from` identifying its coverage. An incomplete total is not a lifetime total, and zero recorded eligible volume is not proof that no trading occurred.

## Concurrency and backpressure

General request-rate limits, history concurrency, delivery limits and live subscriptions are separate controls. Account profiles can override defaults. Read the effective history policy from `/v3/whoami`; do not infer it from advertised requests per second or another customer's configuration.

For `429`, inspect the error code, scope and `Retry-After`. `HISTORY_CONCURRENCY_LIMIT` means your account has occupied its lanes; reduce simultaneous work. `HISTORY_POOL_BUSY` means the shared serving pool is busy; retry with bounded backoff. A five-minute repair timer is a scheduling cadence, not a promise that every backfill completes in five minutes.

## Migration checklist

- Replace cross-venue joins based on `game_slug` or outcome-array position.
- Keep candidate grouping separate from confirmed contract and outcome keys.
- Handle `unmatched`, `needs_review`, null values and mapping revocations explicitly.
- Poll corrections for resolved as well as open markets.
- Stop treating one-second grids, HTTP 200 or total counts as completeness certificates.
- Use per-route identifiers, opaque cursors, effective account limits and retry metadata.
- Re-fetch previously incomplete historical windows where necessary; metadata polling alone cannot repair them.
