diff --git a/docs.json b/docs.json index 3228d68..7d6f4b2 100644 --- a/docs.json +++ b/docs.json @@ -24,6 +24,16 @@ "group": "API Reference", "openapi": "openapi-v1.json" }, + { + "group": "Search & Answers", + "pages": [ + "guides/search-and-ask" + ] + }, + { + "group": "Search & Answers API Reference", + "openapi": "openapi-search-ask-v1.json" + }, { "group": "Guides", "pages": [ diff --git a/guides/search-and-ask.mdx b/guides/search-and-ask.mdx new file mode 100644 index 0000000..e07cd49 --- /dev/null +++ b/guides/search-and-ask.mdx @@ -0,0 +1,218 @@ +--- +title: "Search and Ask" +description: "Retrieve normalized web results or get a fast, source-backed answer." +--- + +## Overview + +Reprompt offers two small, complementary web endpoints: + +- **Search** retrieves normalized web search results for a query. Use it when your application or agent needs the results themselves. +- **Ask** retrieves search results and produces a fast, single-hop narrative answer grounded in those results. Use it when your user needs a concise answer with sources. + +Both endpoints accept the same minimal body. There are no filters, modes, or structured search inputs at launch. + + +`Ask` is a fast grounded-answer endpoint, not a deep-research workflow. It does not perform multi-step research or replace source review for high-stakes decisions. + + +## Authentication and base URL + +Create an API key in [Organization Settings → API Keys](https://app.repromptai.com/organization), then send it as a bearer token. Reprompt resolves the organization from the authenticated API key, so no organization identifier is required in the URL. + +```bash +https://api.repromptai.com/v1 +``` + +## Search + +Send a natural-language query to `POST /search`. The response is a stable, normalized result list; it intentionally does not expose the underlying search-provider response. + + + +```bash cURL +curl --request POST \ + --url 'https://api.repromptai.com/v1/search' \ + --header 'Authorization: Bearer {YOUR_API_KEY}' \ + --header 'Content-Type: application/json' \ + --data '{ + "query": "What is the difference between a web search API and a research agent?" + }' +``` + +```python Python +import requests + +response = requests.post( + "https://api.repromptai.com/v1/search", + headers={ + "Authorization": "Bearer {YOUR_API_KEY}", + "Content-Type": "application/json", + }, + json={ + "query": "What is the difference between a web search API and a research agent?" + }, +) +response.raise_for_status() +print(response.json()) +``` + +```javascript JavaScript +const response = await fetch( + 'https://api.repromptai.com/v1/search', + { + method: 'POST', + headers: { + Authorization: 'Bearer {YOUR_API_KEY}', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + query: 'What is the difference between a web search API and a research agent?' + }) + } +); + +if (!response.ok) throw new Error(`Search failed: ${response.status}`); +console.log(await response.json()); +``` + + + +### Search response + +```json +{ + "query": "What is the difference between a web search API and a research agent?", + "answer_box": { + "answer": "A web search API retrieves ranked web results.", + "url": "https://example.com/search-apis" + }, + "results": [ + { + "title": "Example result title", + "url": "https://example.com/search-vs-research", + "snippet": "A short excerpt describing the result.", + "position": 1, + "date": "2026-07-25" + } + ] +} +``` + +Each item in `results` has a stable normalized shape: + +| Field | Type | Description | +| --- | --- | --- | +| `title` | string | Result title. | +| `url` | string | Canonical result URL. | +| `snippet` | string, optional | Search-result excerpt. | +| `position` | integer | One-based rank in the returned result set. | +| `date` | string, optional | Date supplied by the result, when available. | + +The `results` array can be empty when no results match the query. + +When the search provider supplies them, the response can also include: + +- `answer_box` — a direct answer or featured snippet with its source URL. +- `knowledge_graph` — entity information such as a title, type, description, website, and scalar facts. + +These objects are optional. Build agent logic around `results` unless it explicitly benefits from enriched search features. + +## Ask + +Send the same query to `POST /ask` to receive a concise narrative answer plus the source objects used to ground it. Reprompt uses DeepSeek V4 Flash through OpenRouter for this endpoint. + + + +```bash cURL +curl --request POST \ + --url 'https://api.repromptai.com/v1/ask' \ + --header 'Authorization: Bearer {YOUR_API_KEY}' \ + --header 'Content-Type: application/json' \ + --data '{ + "query": "What is the difference between a web search API and a research agent?" + }' +``` + +```python Python +import requests + +response = requests.post( + "https://api.repromptai.com/v1/ask", + headers={ + "Authorization": "Bearer {YOUR_API_KEY}", + "Content-Type": "application/json", + }, + json={ + "query": "What is the difference between a web search API and a research agent?" + }, +) +response.raise_for_status() +answer = response.json() +print(answer["answer"]) +for source in answer["sources"]: + print(source["title"], source["url"]) +``` + +```javascript JavaScript +const response = await fetch( + 'https://api.repromptai.com/v1/ask', + { + method: 'POST', + headers: { + Authorization: 'Bearer {YOUR_API_KEY}', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + query: 'What is the difference between a web search API and a research agent?' + }) + } +); + +if (!response.ok) throw new Error(`Ask failed: ${response.status}`); +const { answer, sources } = await response.json(); +console.log(answer, sources); +``` + + + +### Ask response + +```json +{ + "query": "What is the difference between a web search API and a research agent?", + "answer": "A web search API returns relevant documents for a query. A research agent typically uses search as one step in a larger, multi-step process that evaluates sources and synthesizes a response. [1]", + "sources": [ + { + "title": "Example result title", + "url": "https://example.com/search-vs-research", + "snippet": "A short excerpt describing the result.", + "position": 1, + "date": "2026-07-25" + } + ] +} +``` + +`sources` uses the same normalized source-object shape as `Search` results. Render the source URLs alongside the answer so people can inspect the evidence themselves. + +## Errors and retries + +Both endpoints return JSON errors. Handle these status codes: + +| Status | Meaning | What to do | +| --- | --- | --- | +| `401` | The API key is missing, invalid, or revoked. | Create or use an active API key. | +| `403` | The authenticated account cannot access the endpoint. | Verify the feature is enabled for the account. | +| `422` | The request is invalid, including a missing, blank, or extra input field; `Ask` also uses this when no web results are available. | Correct the request; do not retry unchanged input. | +| `429` | The account has exceeded a rate or usage limit. | Retry with exponential backoff and respect `Retry-After` when present. | +| `502` | `Ask` could not produce a citation-backed answer from the retrieved sources. | Retry once or reformulate the query. | +| `503` | A search or answer provider is temporarily unavailable. | Retry idempotently with exponential backoff and respect `Retry-After`. | + +For authentication help, see [Troubleshooting Authentication & 40x Errors](/guides/troubleshooting-40x). + +## Pricing + +`Search` costs **$5 per 1,000 requests** ($0.005 per request). `Ask` costs **$5 per 1,000 requests** ($0.005 per request). + +Pricing is per endpoint request. `Ask` includes the search and answer-generation work with no additional token surcharge; do not make an additional `Search` call solely to support the same `Ask` request unless your product also needs the raw result list. diff --git a/openapi-search-ask-v1.json b/openapi-search-ask-v1.json new file mode 100644 index 0000000..5580f76 --- /dev/null +++ b/openapi-search-ask-v1.json @@ -0,0 +1,208 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Reprompt Search and Ask API", + "version": "1.0.0", + "description": "Search returns normalized web results. Ask returns a fast, single-hop narrative answer grounded in web results; it is not a deep-research workflow." + }, + "servers": [ + { + "url": "https://api.repromptai.com/v1" + } + ], + "paths": { + "/search": { + "post": { + "tags": ["Search & Answers"], + "summary": "Search the web", + "description": "Returns a stable, normalized list of web search results.", + "operationId": "search", + "security": [{ "HTTPBearer": [] }], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/QueryRequest" }, + "example": { "query": "What is the difference between a web search API and a research agent?" } + } + } + }, + "responses": { + "200": { + "description": "Normalized web search results.", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SearchResponse" } + } + } + }, + "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { "$ref": "#/components/responses/Forbidden" }, + "422": { "$ref": "#/components/responses/InvalidQuery" }, + "429": { "$ref": "#/components/responses/RateLimited" }, + "503": { "$ref": "#/components/responses/UpstreamFailure" } + } + } + }, + "/ask": { + "post": { + "tags": ["Search & Answers"], + "summary": "Get a fast, source-backed answer", + "description": "Retrieves web results and generates a concise single-hop answer. This endpoint is not intended for deep research.", + "operationId": "ask", + "security": [{ "HTTPBearer": [] }], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/QueryRequest" }, + "example": { "query": "What is the difference between a web search API and a research agent?" } + } + } + }, + "responses": { + "200": { + "description": "A fast narrative answer with its normalized sources.", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/AskResponse" } + } + } + }, + "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { "$ref": "#/components/responses/Forbidden" }, + "422": { "$ref": "#/components/responses/InvalidQuery" }, + "429": { "$ref": "#/components/responses/RateLimited" }, + "502": { "$ref": "#/components/responses/UncitedAnswer" }, + "503": { "$ref": "#/components/responses/UpstreamFailure" } + } + } + } + }, + "components": { + "securitySchemes": { + "HTTPBearer": { + "type": "http", + "scheme": "bearer" + } + }, + "schemas": { + "QueryRequest": { + "type": "object", + "additionalProperties": false, + "required": ["query"], + "properties": { + "query": { + "type": "string", + "minLength": 1, + "maxLength": 1000, + "description": "Natural-language web query." + } + } + }, + "SearchResult": { + "type": "object", + "required": ["title", "url", "position"], + "properties": { + "title": { "type": "string", "description": "Result title." }, + "url": { "type": "string", "format": "uri", "description": "Canonical result URL." }, + "snippet": { "type": "string", "description": "Search-result excerpt." }, + "position": { "type": "integer", "minimum": 1, "description": "One-based result rank." }, + "date": { "type": "string", "description": "Date supplied by the result, when available." } + } + }, + "SearchResponse": { + "type": "object", + "required": ["query", "results"], + "properties": { + "query": { "type": "string" }, + "answer_box": { "$ref": "#/components/schemas/AnswerBox" }, + "knowledge_graph": { "$ref": "#/components/schemas/KnowledgeGraph" }, + "results": { + "type": "array", + "items": { "$ref": "#/components/schemas/SearchResult" } + } + } + }, + "AnswerBox": { + "type": "object", + "properties": { + "title": { "type": "string" }, + "answer": { "type": "string" }, + "snippet": { "type": "string" }, + "url": { "type": "string", "format": "uri" }, + "date": { "type": "string" } + } + }, + "KnowledgeGraph": { + "type": "object", + "properties": { + "title": { "type": "string" }, + "type": { "type": "string" }, + "description": { "type": "string" }, + "website": { "type": "string", "format": "uri" }, + "facts": { + "type": "object", + "additionalProperties": { "type": "string" } + } + } + }, + "AskResponse": { + "type": "object", + "required": ["query", "answer", "sources"], + "properties": { + "query": { "type": "string" }, + "answer": { "type": "string", "description": "Fast narrative answer grounded in the provided sources." }, + "sources": { + "type": "array", + "items": { "$ref": "#/components/schemas/SearchResult" } + } + } + }, + "ErrorResponse": { + "type": "object", + "properties": { + "detail": { "type": "string" } + } + } + }, + "responses": { + "InvalidQuery": { + "description": "The request is invalid, query is missing/blank, or Ask found no web results.", + "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } + }, + "Unauthorized": { + "description": "The API key is missing, invalid, or revoked.", + "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } + }, + "Forbidden": { + "description": "The API key cannot access this organization or endpoint.", + "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } + }, + "RateLimited": { + "description": "A rate or usage limit has been exceeded.", + "headers": { + "Retry-After": { + "schema": { "type": "integer" }, + "description": "Seconds to wait before retrying, when provided." + } + }, + "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } + }, + "UpstreamFailure": { + "description": "A required search or answer provider is temporarily unavailable.", + "headers": { + "Retry-After": { + "schema": { "type": "integer" }, + "description": "Seconds to wait before retrying." + } + }, + "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } + }, + "UncitedAnswer": { + "description": "Ask could not produce a citation-backed answer from the retrieved sources.", + "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } + } + } + } +}