Endpoints
Coverage
What the index holds, per corpus: live record counts, embedding coverage, and the gaps we know about.
/v1/coverageWhat 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 | nullcategoryEntityCategory | nullcategorynarrows the answer to the segments of one category, e.g.companyorpatent.segmentis accepted but does not narrow the answer yet: you get every segment whatever you send. Filter onsegments[].nameyourself.
Response#
as_ofstring | nulldegradationarray of Degradationdetailstringimpact"recall" | "precision" | "freshness" | "fields"reasonDegradationReasonWhy 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 | nullmetaResponseMetaPresent on every 2xx, including the ones that are not paginated.
as_ofstringcredential"api_key" | "session"default: api_keyWhich 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 | nullWhat 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_idstringnot_in_indexarray of stringWhat we know we do not have. Published deliberately — a coverage number without its holes invites exactly the question it cannot answer.
segmentsarray of CoverageSegmentOutcategoryEntityCategory*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 | nullnamestringstaleststring | nulltotalintegerwith_domaininteger | nullwith_embeddingsinteger | nullEach entry in segments describes one corpus:
| Field | Meaning |
|---|---|
name | The corpus: companies, people, affiliations, patents, news, trends, market-reports, fundings, academic-reports, job-openings |
category | The record category the corpus holds |
total | Records in the corpus, counted |
with_embeddings | How many can be ranked by meaning. null where the corpus has no embeddings at all, which is different from 0 |
with_domain | Reserved. Currently always null |
freshest, stalest | Reserved. 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#
| Status | Code | Summary |
|---|---|---|
| 401 | auth.unauthorized | No usable credential (cause deliberately unspecified) |
| 403 | auth.browser_origin | A secret key was used from a browser |
| 403 | auth.insufficient_scope | The credential does not hold the required scope |
| 422 | pagination.cursor_invalid | The cursor could not be read (e.g. a filter changed mid-pagination) |
| 422 | request.invalid | A field failed validation (extra.errors has the detail) |
| 503 | credits.unavailable | The billing service could not confirm the charge; retry with the same Idempotency-Key |
| 503 | upstream.unavailable | The retrieval engine is unreachable (not charged) |
| 504 | upstream.timeout | The retrieval engine did not answer in time (not charged) |