---
title: "API discovery"
method: GET
path: "/api/v1"
tags: ["System"]
---

# API discovery

`GET /api/v1`

Unauthenticated API-origin discovery document pointing agents to the canonical API base URL, full docs, web-origin OpenAPI spec, health check, and the COMPLETE index of authenticated data routes. data.authenticated_routes is the whole authenticated route surface, not a sample: it carries every authenticated route this spec documents, so an agent that starts here never has to guess a path. backend/src/api_v1/discovery.rs::authenticated_routes_match_the_published_spec fails if the index and this spec disagree in either direction.

## Response `200`

API discovery document

- object
  - `object` 'api_discovery', required
  - `data` ApiDiscovery, required
    - `api_base_url` string, uri, required — Canonical API origin for public V1 requests.
    - `docs_url` string, uri, required — Full agent-readable API reference.
    - `openapi_url` string, uri, required — Canonical web-origin OpenAPI JSON document.
    - `health_url` string, uri, required — Unauthenticated API health endpoint.
    - `authentication` 'Bearer API key required for data endpoints; discovery (/api/v1), health, and /api/v1/platforms are public.', required
    - `authenticated_routes` string[], required — The complete authenticated route index: one entry per authenticated route this spec documents, in "<METHOD> <path>" form, not a representative subset. GET /api/v1 is the unauthenticated entrypoint an agent hits first, so it hands back the whole authenticated surface rather than a sample the caller would have to guess around. The example on GET /api/v1 is abridged for readability -- the live response returns all of them. Kept in lockstep with this spec by backend/src/api_v1/discovery.rs::authenticated_routes_match_the_published_spec, which fails in both directions.
  - `meta` ResponseMeta, required
    - `request_id` string, required — Unique request ID (req_ prefix).
    - `cached` boolean, required
    - `cache_age_s` integer, nullable — Cache age in seconds, null if not cached.
    - `cost` integer, required — Advisory request weight (relative compute cost). 1 for simple reads; higher for heavier endpoints. Not a credit/price.
    - `directional_source` 'live' | 'degraded' — Which path produced the team-directional read on this response. Only present on endpoints that compute one (today: GET /api/v1/sports-edge-signals). "live" means the read RAN. "degraded" means it FAILED, so nothing was measured and the ranking fell back to raw conviction. The flag describes the READ, not its consequence: a read that ran and found nothing groupable also leaves the directional fields null, and that is honestly "live" -- the per-signal nulls already say "nothing to enrich here", so this snapshot-level flag carries only what they cannot, namely whether the read ran at all. A degraded response is cached on the shorter degraded TTL so it self-heals. Reported SEPARATELY from ranking_source because the two degradations are independent -- a smart-money DB miss weakens the ranking DATA, a directional failure removes a ranking WEIGHT -- and a consumer down-weighting a degraded response needs to know which input it lost. Omitted on endpoints that compute no directional read.
    - `ranking_source` 'live' | 'db_only' — Which ranking-data path produced this response. Only present on endpoints that can degrade a ranking (today: GET /api/v1/sports-edge-signals). "live" is the normal path (the current holder pile from the provider batch); "db_only" is the degraded fallback (a truthful but weaker trader_markets ranking) served when the live sharp-money ranking batch is unavailable (a smart-money DB read failure, not a Polymarket outage) and cached on a shorter TTL, so a consumer can down-weight or skip it. Omitted on endpoints that never degrade.

## Other responses

- `408` — Request exceeded the server's 30-second transport timeout. The timeout response has an empty body because it is generated before handler-level JSON error shaping.
- `429` — Rate limit exceeded. Two independent budgets. (1) 100 requests/minute per user (sliding window), on every authenticated route. (2) On the BATCH routes only: 2500 batch item units/minute per user, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch, which is the most item work a key can buy through the request limiter at all: a caller may spend their entire 100-request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget still denies at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After before any item work is done.

## Changes

- **2026-07-14** `22ab6cfbf300` — 8 info
  - added the optional property `error/reason` to the response with the `429` status
  - added the optional property `error/retry_at` to the response with the `429` status
  - added the optional property `meta/directional_source` to the response with the `200` status
  - added the optional property `meta/directional_source` to the response with the `429` status
  - …4 more
- **2026-06-15** `5b6d6ff7692c` — 1 breaking
  - the `authentication` response property const value changed from `Bearer API key required for data endpoints; discovery and health are public.` to `Bearer API key required for data endpoints; discovery (/api/v1), health, and /api/v1/platforms are public.` for the status `200`
- **2026-06-01** `422bd4dc1611` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/0xinsider/apis/0xinsider-api/changes/api/v1/get.md)

---

[API](https://skmtc.dev/0xinsider/apis/0xinsider-api.md) · [All operations](https://skmtc.dev/0xinsider/apis/0xinsider-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/0xinsider/0xinsider-api/revisions/dd8d0cd6ca4d/schema)
