Search API
There are two ways to search Reactor search indexes from outside the console. How the text of a search matches, with examples, is on Writing a Search.
- With a search key, from your server, with no loop:
POST /api/indexes/{indexId}/search. - Through a loop, from your server or your page:
POST /api/loops/{loopId}/search.
With a search key
A search key searches the indexes it was minted for, and does nothing else: it starts no run and reads no collection. An owner mints one on the console, on the index’s page under For a server of yours: search keys. The key is shown once; if it is lost, revoke it there and mint another.
A search key cannot search a collection index. A collection holds your account’s records, which can be personal data, and a key’s caller is not your account.
Send the key as Authorization: Bearer rk_… to POST /api/indexes/{indexId}/search, where
indexId is one of the key’s indexes. Keep the key on your server: this route does not answer a
browser on another site, because a key in a page’s source is a key anyone can read.
The body:
{ "query": "what to find", "mode": "hybrid", "rerank": true, "limit": 10 }
queryis required: 1 to 500 characters, matched as words and by meaning.modeishybrid(the default: both),text(the words only) orsemantic(the meaning only).rerankis your account’s setting when absent.falsekeeps the plain order.trueis refused with403when your account turned reranking off for search keys, under Settings > Search order.limitis 1 to 20, 10 when absent.
It answers 200 with results, best first. Each result has the document id in the index, a
title, a heading (where it sits in its document), a snippet (the matching passage as plain
text: a link’s words without its address, and no Markdown marks; see A snippet’s
code), and a url: a crawled page’s
address, or the source an uploaded file named when it was added. reranked says whether a rerank
set the order, and when it did not, rerank_reason says why (see Why a search was not
reranked). A result is text from your indexed documents, so show
it as text.
Each call is charged one search at the published price on Pricing, and one
rerank more when reranked is true, and only then: an all_too_weak answer is not charged a
rerank on this route. A call your wallet cannot cover answers 402 and charges nothing. A refused
call is never charged.
The refusals say what to fix:
| Status | When |
|---|---|
400 | The body is not one this route takes. |
402 | Your wallet cannot cover the search. |
403 | No key, a key that is not a search key, a revoked key, a key that does not search this index (the message names the ones it does), or a rerank your account turned off. |
404 | The index is gone, or is a collection index. |
429 | Over the rate limit. Retry-After says when to try again. |
503 | Search could not run just now; try again. |
Through a loop
POST /api/loops/{loopId}/search searches what the loop’s published version searches, minus
every collection index. loopId is the loop’s public id (pl_…). It takes an API key with the
search scope, for a loop that declares api delivery, or the visitor credential the embed and
the SDK hold. A search key is not taken here.
The body is {"query": {"text": "what to find"}}. The text is 1 to 500 characters. Add
"match" to change how it is found: "exact" finds the words together and in order, "fuzzy"
allows a typo in each word, and "regex" reads the text as a pattern for one whole word, such as
deploy.*. Add "limit" for at most that many results (10 when absent, at most 20). Any
other form of query, such as a boolean or a raw query, answers 400. A pattern too broad to
search answers 400 with what to change: start it with a few fixed letters and use fewer
wildcards.
modeishybrid(the default: both),text(the words only) orsemantic(the meaning only), as on the index route.rerankis your account’s setting for visitors when absent.falsekeeps the plain order.trueis refused with403when your account turned reranking off for visitors, under Settings > Search order.
Each search is charged by the same prices and held to the same budgets whatever it asks for. The
amount follows what ran: a search by words only embeds nothing, and a rerank is charged whenever
the reranking model ran. That includes an answer whose rerank_reason is all_too_weak, which
is not reranked; every other answer that is not reranked is not charged a rerank.
It answers 200 with results: each one has a title, a heading (where it sits in its
document), a snippet (the matching passage as plain text, with no Markdown marks; see A snippet’s
code), and a url:
a crawled page’s address, or the source an uploaded file named when it was added. took_ms is how long the search took, and reranked says whether the
reranker ordered the results; when it did not, rerank_reason says why. The answer never carries a cost. A result is text from the indexed
documents, so show it as text. A loop with nothing a visitor may search answers 404. A search
the wallet or the loop’s budgets cannot cover answers 503, the same answer as a search that
could not run.
A snippet’s code
A snippet keeps its prose on one line. When the passage holds code, the code keeps its own lines and indentation, and it comes between two lines that start with three backticks. The first of the two can name the language:
Configure the sidebar:
```js
window.$docsify = {
loadSidebar: true,
};
```
Then reload the page.
A snippet never starts inside code. When it stops inside code, it keeps whole lines, closes the
code with its own backtick line, and ends with a line that is only …: show that mark as the code’s
last line, so a reader sees that more code follows. To show a snippet, split it at those lines: show the prose as text
and the code as preformatted text. Never render a snippet as Markdown or HTML, because it is text
from your indexed documents.
Why a search was not reranked
Both routes answer rerank_reason when reranked is false, and leave it out when it is true. The
results are then in the search’s own order, which ranks the words and the meaning together.
rerank_reason | What happened |
|---|---|
off | The rerank was not asked for, or your account turned it off for this route. |
all_too_weak | The reranking model ran and scored every match too weak to show, so the closest matches by words and meaning are shown. Through a loop this is charged a rerank, because the model ran; with a search key it is not. |
budget | The reranking model did not answer in time. |
error | The reranking model did not answer. |
malformed | The reranking model’s answer could not be read. |
not_covered | The wallet cannot cover the rerank. |
no_text | The query has no words to score the results by. |
floor | A loop that searches the index needs a stronger model than the reranking model. |
flag | The ordering setting could not be read. |