Endpoints

Coverage

What the index holds, per corpus: live record counts, embedding coverage, and the gaps we know about.

GET/v1/coverage

What the index holds, per corpus

Per-corpus totals and embedding coverage — the runtime answer to "which categories are real in this deployment". Gate category pickers on this rather than hard-coding the schema's list.

Scope: dsp.search.read

Use it when you need to know what the index holds before you build on it: which categories are live in this deployment, how many records each one has, and how many of them can be searched by meaning. Outcome: one segment per corpus with counted (not estimated) totals, plus the gaps we know we have.

This route is free and needs dsp.search.read. The counts are taken from the index when you call, so gate a category picker on this response rather than on a hard-coded list.

Request#

segmentstring | null
categoryEntityCategory | null
  • category narrows the answer to the segments of one category, e.g. company or patent.
  • segment is accepted but does not narrow the answer yet: you get every segment whatever you send. Filter on segments[].name yourself.

Response#

as_ofstring | null
degradationarray of Degradation
detailstring
impact"recall" | "precision" | "freshness" | "fields"
reasonDegradationReason

Why an answer is less than it should be. Closed, because a client that cannot branch on the reason can only show the user a shrug. These are the honest constraints — partial vector coverage, smry mapped as keyword so it cannot be scored lexically, a federated corpus being unreachable — surfaced at runtime instead of in a footnote.

source_corpusSourceCorpus | null
metaResponseMeta

Present on every 2xx, including the ones that are not paginated.

as_ofstring
credential"api_key" | "session"default: api_key

Which credential produced this response. session means the dashboard playground ran it as the signed-in user rather than as an API key — so it is billed to the user, subject to interactive rate limits, and carries no integration compatibility guarantee. Additive and defaulted, so it breaks no existing client.

credits_chargednumber | null

What this request cost, in credits, to at most three decimals. 0 when it cost nothing: a Basic or AI search that found nothing, rows this search already paid for (a cursor sent again, or a request repeated with the same Idempotency-Key on the same UTC day), or a test key. A request without a cursor or a repeated key is a new search, so keep the first page rather than asking for it again. null on a free endpoint.

environment"live" | "test"

Echoed on every response so a developer can never mistake a test-key result for a live one.

request_idstring
not_in_indexarray of string

What we know we do not have. Published deliberately — a coverage number without its holes invites exactly the question it cannot answer.

segmentsarray of CoverageSegmentOut
categoryEntityCategory

*What* to search, and what a returned row is. One parameter carries both, because they are the same fact: a search of patent returns patents. The alternative — a source/vertical selector beside a narrower category — lets a caller ask for patents from the people index, a combination that has no meaning and would need rejecting at runtime. A closed set that cannot express the contradiction is better than a validator that catches it. Values are exactly prism's own row types, so category in the request and results[].category in the response are always the same string. company and person are the GTM index; the rest are separate corpora with their own filters, freshness and coverage. Not everything applies everywhere: see SearchRequest, which rejects the GTM-only parameters rather than ignoring them. job_opening is a document corpus like patent/news_article/etc — a posting, not an entity — but its records carry a domain (the posting company's) all the same. It is deliberately not in GTM_CATEGORIES (that set is about the entity/document distinction, and a job posting is still a document), but it *is* in DOMAIN_FILTERABLE_CATEGORIES, which exists specifically to separate those two axes.

fresheststring | null
namestring
staleststring | null
totalinteger
with_domaininteger | null
with_embeddingsinteger | null

Each entry in segments describes one corpus:

FieldMeaning
nameThe corpus: companies, people, affiliations, patents, news, trends, market-reports, fundings, academic-reports, job-openings
categoryThe record category the corpus holds
totalRecords in the corpus, counted
with_embeddingsHow many can be ranked by meaning. null where the corpus has no embeddings at all, which is different from 0
with_domainReserved. Currently always null
freshest, stalestReserved. Currently always null

not_in_index lists what we know we do not have, such as private companies with no web or LinkedIn presence. as_of is when the counts were taken. A corpus that could not be counted is left out of segments and named in degradation (reason corpus_unavailable), so a missing segment never reads as "we have none".

Errors#

StatusCodeSummary
401auth.unauthorizedNo usable credential (cause deliberately unspecified)
403auth.browser_originA secret key was used from a browser
403auth.insufficient_scopeThe credential does not hold the required scope
422pagination.cursor_invalidThe cursor could not be read (e.g. a filter changed mid-pagination)
422request.invalidA field failed validation (extra.errors has the detail)
503credits.unavailableThe billing service could not confirm the charge; retry with the same Idempotency-Key
503upstream.unavailableThe retrieval engine is unreachable (not charged)
504upstream.timeoutThe retrieval engine did not answer in time (not charged)