Ask API
The Ask API lets your own systems talk to your assistant: a support tool, an internal agent, an AI client, a backend job. You send a question and get back the answer the assistant would give a visitor, with its persona, guardrails and knowledge base, and the sources it used.
Use the Knowledge Base API instead when you want the raw matching passages and will write the answer yourself.
Authentication and scope
Section titled “Authentication and scope”Send an API key with the assistant:ask scope as a bearer token. See API Keys for creating one.
Every ask spends AI credits, so the scope is separate from assistant:read and assistant:write: a key that manages the assistant’s instructions cannot run up usage, and a key that asks questions cannot change how the assistant behaves.
POST /api/v1/projects/{projectId}/assistant/ask
Section titled “POST /api/v1/projects/{projectId}/assistant/ask”curl -X POST https://your-ragtime-instance.com/api/v1/projects/{projectId}/assistant/ask \ -H "Authorization: Bearer rt_live_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{ "question": "How long do refunds take for enterprise customers?" }'{ "answer": "Enterprise refunds are processed within 14 days of the request.", "conversationId": "7f0e2a5c-3b1d-4e6f-9a8b-0c1d2e3f4a5b", "usedKnowledgeBase": true, "citations": [ { "id": "a1b2c3d4-…", "name": "Refund policy 2026", "type": "pdf", "pages": [2] } ], "language": "English", "confidence": "high"}Request fields
Section titled “Request fields”| Field | Type | Description |
|---|---|---|
question |
string | Required. What to ask. |
history |
array | Optional. Earlier turns of this conversation, oldest first, as { "role": "user" | "assistant", "content": "…" }. At most 50. |
conversationId |
string (UUID) | Optional. The conversationId a previous answer returned, to continue that conversation. |
language |
string | Optional. Answer in this language, as a name or code (Dutch, nl). An unsupported language is a 400. |
stageId |
string | Optional. The stageId a previous answer returned, for assistants with conversation stages. |
draft |
boolean | Optional. Answer as the unpublished draft. Needs the assistant:draft scope. See Testing the draft. |
end |
boolean | Optional. This is the last turn: file the conversation for Insights now. See Ending a conversation. |
Unknown fields are rejected with 400 invalid_request.
Response fields
Section titled “Response fields”| Field | Description |
|---|---|
answer |
The assistant’s answer, as plain text. |
conversationId |
The conversation this turn belongs to. Send it back to continue. |
usedKnowledgeBase |
Whether the answer drew on the knowledge base. |
citations |
The sources the answer used: id, name, and type and pages when known. Empty unless the assistant is set to cite its sources. |
language |
The language the assistant answered in. |
confidence |
The assistant’s own confidence label. |
stageId |
The conversation stage after this turn, for assistants with stages. |
followUps |
Suggested follow-up questions, when the assistant offers them. |
notices |
Anything that affected the answer, such as libraries skipped because they use a different embedding model. |
draft |
true when the draft answered. Absent otherwise. |
Conversations
Section titled “Conversations”The API is stateless: it does not remember earlier turns for you. To continue a conversation, send the earlier turns in history and the conversationId from the previous answer:
{ "question": "And for monthly plans?", "conversationId": "7f0e2a5c-3b1d-4e6f-9a8b-0c1d2e3f4a5b", "history": [ { "role": "user", "content": "How long do refunds take for enterprise customers?" }, { "role": "assistant", "content": "Enterprise refunds are processed within 14 days of the request." } ]}conversationId is also what Ragtime counts conversations by. Calls that share one count as one conversation in analytics and against your plan’s conversation allowance. A call without one starts a new conversation, so send it back on every follow-up.
Transcripts and Insights
Section titled “Transcripts and Insights”When the project keeps transcripts (Insights settings, storeTranscripts), API conversations reach Insights like the widget’s do, labelled API in the Transcripts tab. Because a server never says a conversation is over, Ragtime files it once it has been quiet for 30 minutes:
- The transcript is the last ask’s
history, its question and the answer. Send the full history on each follow-up, or the transcript only has what you sent. - Personal information is removed before it is stored, and the conversation is analyzed for Insights, as with every transcript.
- An ask with the same
conversationIdafter it was filed picks the conversation up again. It is filed again in full, replacing the earlier copy. - A key billed to a channel files its conversations under that channel.
Ending a conversation
Section titled “Ending a conversation”If you run conversations one after another, end each one when it is over, so it is filed at once instead of after 30 minutes. Either send "end": true with the last question, or call:
curl -X POST https://your-ragtime-instance.com/api/v1/projects/{projectId}/assistant/conversations/{conversationId}/end \ -H "Authorization: Bearer rt_live_YOUR_KEY_HERE"{ "conversationId": "7f0e2a5c-3b1d-4e6f-9a8b-0c1d2e3f4a5b", "status": "closing" }It needs assistant:ask and is safe to repeat. status is closing when the conversation is now being filed, and nothing_to_file when there is no open conversation by that id: it was never asked, it was already filed, or the project does not keep transcripts. Asking again with the same conversationId afterwards picks the conversation up again.
What the assistant answers with
Section titled “What the assistant answers with”- The published version. The API answers with the assistant as last published. If nothing is published yet, the call returns
409 conflict. To try changes before publishing, see Testing the draft. - Your key’s audiences. Retrieval uses only the libraries your key may see: unrestricted libraries, plus audience-restricted libraries that match the key’s retrieval audiences.
- No guided forms. Forms need a screen to fill in, so the assistant does not start them over the API.
Testing the draft
Section titled “Testing the draft”Send "draft": true to get the answer from the draft: the assistant as it is being edited in the dashboard, before you publish it. It works even before the first publish.
- Its own scope. The key needs
assistant:draftas well asassistant:ask. Give it only to keys for testing. A production key without it cannot reach the draft, so half-finished changes never reach your users by accident. - Test traffic. Draft answers spend AI credits like any other, but they are kept out of Insights, transcripts and analytics, as the dashboard’s preview is.
- Not checked. The draft has not been through the checks that run when you publish.
Credits
Section titled “Credits”Every ask spends AI credits: an embedding for retrieval, and the assistant’s model for the answer. It also counts against the organization-wide rate limit.
Which credits it spends depends on the key:
- A key bound to a channel draws on that channel’s package, exactly as the channel’s own conversations do. When the package’s credits run out, it falls back to the general pool unless the package bills its extra.
- A key without a channel draws on the organization’s general pool.
You choose the channel when you create the key. GET /api/v1/context and GET /api/v1/usage report the pool a key draws on. See AI credits.
Errors
Section titled “Errors”Errors use the standard shape. Specific to this endpoint:
| Status | code |
Meaning |
|---|---|---|
| 402 | credits_exhausted |
The key’s credit pool is used up. |
| 403 | forbidden |
The organization is closed, or the key is bound to a kiosk channel that is switched off or outside its package term. |
| 404 | not_found |
The project has no assistant. |
| 409 | conflict |
The assistant has not been published, or no AI provider is configured. |
| 429 | rate_limited |
The key, the organization (details.bucket: "org") or the AI provider (details.bucket: "provider") is rate limiting. Wait retryAfter seconds. |
| 500 | internal |
The assistant could not answer. Safe to retry once. |