Skip to content

POST /answer

1 min read

Asks the assistant one question and returns the answer, with the documents it came from. This is the endpoint the website widget uses, and the one to use for your own integration.

POST https://answers.snoowl.com/api/v1/answer
Authorization: Bearer ansk_…
Content-Type: application/json

Accepts a secret key, a website key or a preview key. See Keys.

FieldTypeRequiredDescription
questionstringYesThe customer’s question. Leading and trailing spaces are trimmed. 1 to 2,000 characters.
historyarrayNoThe conversation so far, oldest first, as { "role": "user" | "assistant", "content": "…" } objects. Only the last six are used. Other roles are ignored.
session_idstringNoYour ID for this conversation. Shown in Conversations to group its answers. Up to 80 characters are kept.

Send history for follow-up questions. Without it, a question such as “and on the yearly plan?” can’t be understood. Include the assistant’s earlier answers as assistant turns, and leave out the question you’re asking now. Long turns are shortened: the assistant reads up to 1,000 characters of each.

Any other fields are ignored. In particular, the model and tone always come from Assistant settings.

curl https://answers.snoowl.com/api/v1/answer \
  -H "Authorization: Bearer YOUR_ENDPOINT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"question": "How do I get a refund?"}'

A follow-up question, with the conversation so far:

{
  "question": "And on the yearly plan?",
  "history": [
    { "role": "user", "content": "How do I get a refund?" },
    { "role": "assistant", "content": "You can ask for a refund within 30 days of paying, from Billing › Invoices." }
  ],
  "session_id": "chat-8f41c2"
}

A 200 with the answer:

{
  "answer": "Yearly plans can be refunded within 30 days of paying. After that, the plan runs to the end of its year.",
  "status": "answered",
  "citations": [
    {
      "doc": "Refunds",
      "url": "https://help.example.com/billing/refunds",
      "quote": "Annual plans: you can ask for a full refund within 30 days of payment. After 30 days, the plan stays active until the end of the billing year…"
    }
  ],
  "latency_ms": 1840,
  "answer_id": "3f2a9c1e5b7d40a8b1c2"
}
FieldTypeDescription
answerstringThe answer, or your decline message. May contain light Markdown: **bold**, `code`, - bullets and 1. steps.
statusstringanswered, or declined when your documents don’t cover the question.
citationsarrayThe documents the answer used, one entry per document, in the order used. Empty when declined.
citations[].docstringThe document’s name: the file name, the page title, or the name you gave pasted text.
citations[].urlstring or nullThe page’s address, for documents added as a web page or from a sitemap. null for files and pasted text.
citations[].quotestringThe passage the answer used, up to 280 characters, with … when shortened.
latency_msintegerHow long the answer took on Snoowl’s side, in milliseconds.
answer_idstringThis answer’s ID. Send it to POST /feedback with a thumbs up or down.

A declined answer looks like this:

{
  "answer": "I'm sorry, I can't find that in our documentation. Please contact our support team.",
  "status": "declined",
  "citations": [],
  "latency_ms": 420,
  "answer_id": "9b07e4d2a1c34f5e8d6a"
}

Use status, not the text, to tell the two apart. For example, offer a “Contact support” button when status is declined.

Errors use the error format every endpoint uses. The ones to expect here:

StatusWhy
400question is empty or over 2,000 characters
401The key is missing, unknown or revoked
402The workspace’s prepaid balance is used up
403A website key used from a site that isn’t on its list
429The key’s per-minute limit or monthly cap is reached
503The answer couldn’t be written just now. Retry after a short wait. Not charged.

Each answer is charged and logged in Conversations. See Billing.