---
title: "Coverage passport — what each data source holds, from when, with which caveats"
method: GET
path: "/api/coverage/"
tags: ["coverage"]
---

# Coverage passport — what each data source holds, from when, with which caveats

`GET /api/coverage/`

One object per data source: `publisher_news` (GDELT GKG, publisher
RSS, Google News), `sec_form4`, `sec_form8k`, `sec_form6k`,
`earnings_reads`, `earnings_schedule` and `economic_calendar`. Each
carries its earliest and latest row, the last ingest time, the row
count in the source's own unit, the collector's cadence, a history
note saying where the history is thin, the known limits, and the
per-plan archive horizon. Read this before backtesting or promising
coverage downstream: `first_row_at` is the earliest row we hold, NOT
the start of dense coverage — `history_note` says which months are
thin (publisher news densified in June 2026; Form 4 before May 2026
is an unenriched replay; 8-K history starts June 2026; 6-K and
earnings reads start 2026-07-28).

The passport is computed once a day (03:50 UTC) and served from a
cache: `as_of` is when the counts were taken and `generated_at` when
the payload was assembled, so both describe the computation, never
the response. Rows may be up to a day newer than `last_row_at`. On a
cold cache the first caller computes it (a few seconds); a concurrent
caller gets `503` with `Retry-After` instead of a second scan.

`stale` is an honest flag, not an alert: true when the newest ingest
is older than `stale_after_seconds` — six poll cycles for the
collectors, three days for SEC filings (EDGAR takes no filings on
weekends), ten days for earnings reads — or, for the economic
calendar (`stale_after_seconds` null), when no future occurrence is
held. `publisher_news` additionally reports each discovery channel
(`gkg`, `rss`, `gnews`) with its own last ingest and flag.
`research_only` restates that everything described here is
AI-generated financial information for research, not investment
advice.

## Response `200`

The passport, one object per source in a fixed order.

- Coverage
  - `generated_at` string, date-time, required — When the cached payload was assembled (UTC).
  - `as_of` string, date-time, required — The instant the counts were taken (UTC). Up to a day older than the response — the passport is recomputed daily, not per request.
  - `research_only` boolean, required — Always `true`. Research information, not investment advice.
  - `sources` CoverageSource[], required — Fixed order: publisher_news, sec_form4, sec_form8k, sec_form6k, earnings_reads, earnings_schedule, economic_calendar. A source with no rows is still present, with null dates and `rows_total: 0`.
    - `source` 'publisher_news' | 'sec_form4' | 'sec_form8k' | 'sec_form6k' | 'earnings_reads' | 'earnings_schedule' | 'economic_calendar', required
    - `first_row_at` string, date-time, nullable — Earliest row by the source's own clock (article publish time, filing acceptance time, scheduled date at 00:00 UTC). The earliest row we hold, NOT the start of continuous coverage — see `history_note`.
    - `last_row_at` string, date-time, nullable — Latest row by the same clock. For `earnings_schedule` and `economic_calendar` this reaches into the future (scheduled dates).
    - `last_ingested_at` string, date-time, nullable — Arrival clock: when the newest row landed (`created_at`); for `earnings_schedule` the sync's last touch, for `economic_calendar` the last change to the calendar.
    - `rows_total` integer, required — Rows in the source's own unit: articles for `publisher_news`, distinct filings (accession numbers) for `sec_form4`, filings for `sec_form8k` / `sec_form6k`, published reads for `earnings_reads`, confirmed dates for `earnings_schedule`, occurrences for `economic_calendar`.
    - `cadence` string, required — How and how often the source is collected, in plain words.
    - `history_note` string, required — Where the history is thin or starts: the caveat you would otherwise discover by probing the feed.
    - `limits` string[], required — Known scope limits of the source (what is deliberately not collected).
    - `archive_days` CoverageArchiveDays
      - `free` integer, required — Days; 0 means unlimited.
      - `basic` integer, required
      - `pro` integer, required
    - `stale` boolean, required — `true` when `last_ingested_at` is older than `stale_after_seconds`, or — for `economic_calendar`, where `stale_after_seconds` is null — when no future occurrence is held. An honest flag, not an alert.
    - `stale_after_seconds` integer, nullable — The horizon `stale` keys on: six poll cycles for the collectors, three days for SEC filings, ten days for earnings reads; `null` for the economic calendar.
    - `channels` CoverageChannel[], nullable — Only on `publisher_news` — the three discovery channels.
      - `channel` 'gkg' | 'rss' | 'gnews', required
      - `cadence` string, required
      - `last_ingested_at` string, date-time, nullable
      - `stale_after_seconds` integer, required
      - `stale` boolean, required

## Other responses

- `401` — Missing or invalid API key.
- `429` — Rate limit exceeded — either the per-minute burst cap or the per-day volume cap. The `Retry-After` header is the earliest second a retry can succeed, not a guess (a burst block is short, ≤60s; a day-cap block is capped at 3600s — the true reset is `X-RateLimit-Reset`). The `X-RateLimit-*` trio shows the daily volume budget. The body's `extra` names your tier, its `limit_per_minute` / `limit_per_day`, `retry_after_seconds`, and — below Pro — an `upgrade` block with the higher tiers' caps and the pricing URL. A rejected request does not itself consume quota, so retrying after `Retry-After` costs you nothing extra.
- `503` — The passport is not cached and another request is computing it. `Retry-After` (30 s) is when the fresh payload will be there; the body's `extra` carries `reason: coverage_unavailable` and `retry_after_seconds`.

## Changes

- **2026-09-23** `18d41c7cf86d` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/alphai/apis/alphai-rest-api/changes/api/coverage/get.md)

---

[API](https://skmtc.dev/alphai/apis/alphai-rest-api.md) · [All operations](https://skmtc.dev/alphai/apis/alphai-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/alphai/apis/alphai-rest-api/revisions/44fde16b286e?raw)
