POST /v2/indices/{index public key}/conversations
POST /v2/indices/{index public key}/conversations/{conversation_id}
Ask a question and receive an AI-generated answer based on the content in your index, together with the sources used to create the answer.
Answers are turn-based. The first request starts a new conversation and returns a conversation_id. Sending this ID in the path of the following requests keeps the earlier questions and answers as context. This lets visitors refine or narrow a request without having to repeat it.
These endpoints are also used by the AI Conversations widget.
Start a new conversation
Send the visitor’s first question without a conversation_id. The response contains the conversation_id to use for every following turn.
Set ai_conversations to true when starting a conversation. Without it, the endpoint returns a single answer that cannot be continued. This results in the response having no question_id, and posting a follow-up question to the returned conversation_id fails.
POST /v2/indices/{index public key}/conversations
{
"question": "What is AddSearch?",
"ai_conversations": true
}
Continue a conversation
Add each follow-up question to the same conversation by adding the conversation_id to the path. The question is interpreted in the context of the earlier turns, so references such as “the second one” or “in blue” are resolved against the conversation history.
POST /v2/indices/{index public key}/conversations/bf9e6055-59f7-42ac-8198-5bbc4e85b57b
{
"question": "What did I ask before this?"
}
Path parameters
| Parameter | Description | Type | Notes |
|---|---|---|---|
| index public key | The public site key | string | A site key is an identifier of your AddSearch account that can be found in the dashboard |
| conversation_id | The id of an existing conversation | string | Returned in the response of the first request of a conversation. Must be exactly 36 characters long. Leave out of the path when starting a new conversation. |
Request body parameters
| Parameter | Description | Type | Notes |
|---|---|---|---|
| question | The visitor's question | string | Required. 500 characters or less, and cannot be empty. |
| ai_conversations | Enables a conversation that can be continued | boolean | Set to true when starting a new conversation. If left out, a single answer is returned that cannot be continued. Optional for the following turns of the same conversation. |
| streaming | Returns the answer as a server-sent event stream | boolean | The default is false. See "Streaming responses". |
| filter | Limits the documents used to compose the answer | object | Uses the same filter syntax as the Search API |
The optional parameters of the AI Answers feature can also be used with these endpoints to control how the answer is generated.
Sample request
curl --request POST \
'https://api.addsearch.com/v2/indices/YOUR_SITEKEY/conversations' \
--header 'Content-Type: application/json' \
--data-raw '{
"question": "What is AddSearch?",
"ai_conversations": true
}'
Response
Both endpoints return the same response structure.
{
"response": {
"conversation_id": "bf9e6055-59f7-42ac-8198-5bbc4e85b57b",
"question_id": "d058bbb8-f00b-45df-8088-06befafe4e42",
"answer": "AddSearch is a hosted site search service that indexes your content and returns search results and AI-generated answers.",
"sources": [
{
"id": "69fc685283926a5ec5a15e92e6510e96",
"title": "Example document title",
"url": "https://www.example.com/document",
"last_updated_date": "2018-06-20T23:09:09"
}
]
},
"errors": [],
"status": 200
}
| Field | Description | Type | Notes |
|---|---|---|---|
| conversation_id | The id of the conversation | string | 36 characters long. Add it to the path of the following requests to keep the earlier turns as context. |
| question_id | The id of the question | string | Identifies a single turn of the conversation. Returned when the conversation was started with ai_conversations set to true. |
| answer | The generated answer | string | Formatted as Markdown |
| sources | The documents the answer was composed from | array, an array of objects | Empty when no matching content was found in the index |
| sources[].id | Document's id | string | |
| sources[].title | Document's title | string | |
| sources[].url | Document's URL | string | |
| sources[].last_updated_date | The time the document was last updated | string | E.g. "2018-06-20T23:09:09" |
| errors | The problems found with the request | array | Empty on a successful request |
| status | The HTTP status code of the response | int |
Store the conversation_id from the first response and reuse it for the whole conversation.
To start a new conversation, for example when a visitor clears the chat history, call the endpoint again without a conversation_id. The response contains the conversation_id to use for every following turn.
Streaming responses
Add "streaming": true to the request body to receive the answer as it is generated. There is no separate streaming endpoint. The URLs are the same for both the first question and the follow-up questions.
{
"question": "What is AddSearch?",
"ai_conversations": true,
"streaming": true
}
The response is a server-sent event stream with the content type text/event-stream. Each event is a JSON object on a data: line, and the type field tells you how to handle it.
data: {"type": "metadata", "question_id": "d058bbb8-...", "conversation_id": "bf9e6055-..."}
data: {"type": "token", "content": "AddSearch is "}
data: {"type": "token", "content": "a hosted site search service"}
data: {"type": "sources", "sources": [{"id": "...", "title": "...", "url": "...", "last_updated_date": "..."}]}
data: {"type": "done", "execution_time": 7.39}
| Event type | Description | Fields |
|---|---|---|
| metadata | Sent first, before any part of the answer | question_id, conversation_id |
| token | A chunk of the answer. Repeated until the answer is complete. Concatenate the content values to build the full answer. | content |
| sources | The documents the answer was composed from | sources |
| token_usage | Diagnostic information about the request. Can be ignored by your client. | |
| done | The final event of a successful stream. Closes the stream. | execution_time |
| error | The answer could not be generated. The response status stays 200 OK. | message |
The metadata event is always sent first. Read the conversation_id from this event when using streaming.
Concatenate the content values of the token events to build the full answer.
The done event closes the stream.
Your client may also receive event types that are not listed above. Ignore any event type you do not handle, as new types can be added later without notice.
Related keyword search
To show keyword search results next to a conversational answer, use the Refine Query endpoint. It turns the current question and the conversation history into a single search term you can pass to the Search API.
Errors
On a successful request errors, an empty array is returned and status repeats the HTTP status code.
When a request fails, errors lists the problems found, and the fields of a successful response are not present.
The status field is not included in every error response, so use the HTTP status code as the primary signal.
| Status | Meaning | Response body |
|---|---|---|
| 200 OK | The request succeeded | errors is an empty array |
| 400 Bad Request | The request body could not be parsed, or conversation_id is not 36 characters long | {"code": 400, "message": "Unable to process JSON"}, or an errors array describing the path parameter |
| 404 Not Found | No conversation exists for the given conversation_id | {"errors": ["Conversation not found"], "status": 404} |
| 405 Method Not Allowed | A method other than POST was used | {"code": 405, "message": "HTTP 405 Method Not Allowed"} |
| 422 Unprocessable Entity | The question is empty or longer than 500 characters | {"errors": ["question is too long"]} |
| 429 Too Many Requests | The rate limit was exceeded | Empty |
| 500 Internal Server Error | The request could not be processed. For example, a follow-up question sent to a conversation that was not started with ai_conversations set to true. | {"errors": [...], "status": 500} |
When streaming, a failure that happens before the stream opens is returned as an ordinary HTTP error response.
Once the stream is open, failures arrive as an event with the type error and a message field, while the response status stays 200 OK.
Always check the event types as you read the stream instead of relying on the status code alone.
Rate limits
This endpoint is limited to 5 requests per second from one IP address. Requests exceeding the limit return a 429 Too Many Requests response with an empty body. If rejected, throttle concurrent requests in your client and retry after a short delay. See Rate limits for details.