Docs chat API and chat hooks
Authenticate with the project API key#
Every call sends the project's API key as a bearer token.
- Open Settings ▸ Domain & API and find the API Key card.
- Copy the key. It starts with
dbk_. - Send it on each request as
Authorization: Bearer dbk_….
Reset key on the same card issues a new key and revokes the old one at once.
Keep the key on your server. It can change your project's settings and spend your balance, so it must never ship in a browser bundle or a mobile app.
Ask a question#
One call returns one finished answer as JSON; the endpoint does not stream.
/api/v1/chatAsk the project's documentation a question and get back the answer, its sources and three follow-up questions — the same retrieval and model call as the chat on your site.
Missing questionMissing Bearer token, Invalid API keyplan_restrictedtoken_limit_reached, ai_reserve_reached, source_limit_reached, daily_limit_reachedblocked_by_hook, model_call_failed, answer_not_parseablecurl -X POST '/api/v1/chat' \
-H 'Content-Type: application/json' \
-d '{"question":"<question>"}'{
"answer": "Rotate a key from the API keys page … [ref:guides/api-keys|API keys||Rotate a key]",
"refs": [
{
"pagePath": "guides/api-keys",
"pageTitle": "API keys",
"headingText": "Rotate a key",
"headingId": "rotate-a-key"
}
],
"follow_up_questions": [
"Do old keys stop working right away?",
"Can I have two keys at once?",
"Where do I see when a key was created?"
]
}answer is markdown. With Semantic Search on, it carries an inline [ref:…] marker after each cited sentence and refs lists those pages, headingId being the anchor on the rendered page. With it off, refs comes back empty.
Call it from your server#
curl -X POST https://docsbook.io/api/v1/chat \
-H "Authorization: Bearer $DOCSBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"question": "How do I rotate an API key?"}'const res = await fetch("https://docsbook.io/api/v1/chat", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.DOCSBOOK_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ question: "How do I rotate an API key?" }),
})
const { answer, refs, follow_up_questions } = await res.json()An API call is billed like a reader's question.
- Balance — it draws on your balance by the tokens it used, at the price shown on AI Visitors Chat Model; there is no separate API quota.
- Your own key — answers made with Your own AI API Key are billed by your provider.
- Events — each call fires
chat_question_asked, pluschat_no_answerwhen the chat didn't know, so alerts and trigger cards see API questions too.
Chat hooks: your code around every answer#
Chat hooks are three HTTPS URLs of yours that Docsbook calls around every answer — on your site, over this API and through ask_project_docs.
| Hook | When Docsbook calls it | What it sends | Can it change the answer? |
|---|---|---|---|
| Pre-hook | First, before search and the model; waits up to 5 seconds | question, session_id, workspace_id |
Yes — block the question or add context |
| Post-hook | After the answer; does not wait | question, answer, tool_calls, latency_ms, workspace_id, session_id |
No |
| Streaming hook | With the post-hook; does not wait | event (message), question, answer, refs, workspace_id, session_id, latency_ms |
No |
tool_calls lists the pages the answer read, one { "tool": "read_page", "path": … } each. Every hook request is a POST with a JSON body and a 5-second timeout.
What the pre-hook can return#
The pre-hook can stop a question or add to it. Reply with one of these, or with nothing.
{ "block": true, "reason": "Contract pricing comes from your account manager." }{ "inject_context": "This reader is on the Enterprise plan, region EU." }block: true— stops before search and the model, so nothing is billed. The chat on your site shows "Sorry, I could not answer that."; the API returns502withblocked_by_hookand yourreason.inject_context— added to the chat's instructions for this one question.- Anything else — a non-2xx status, a body that isn't JSON, or no reply within 5 seconds, and the chat answers as if no hook were set.
Set and test hooks#
Set hooks from your agent with set_chat_hooks; there is no form for them in the panel. URLs must be https://, and an empty string clears one.
{
"workspace_id": "acme/docs",
"pre_url": "https://api.example.com/docsbook/pre?token=YOUR_SECRET",
"post_url": "https://api.example.com/docsbook/post?token=YOUR_SECRET"
}- Test —
test_chat_hookwithhook_typeset topre,postorstreamingposts{ "test": true, … }to that hook and returns its status code, latency and the first 500 characters of its reply. - Over REST —
POST /api/v1/set_chat_hookstakes the samepre_url,post_urlandstreaming_urlwith your API key. - Not a hook — the chat's other URL, the Call To Action URL, is a link the chat offers readers.
Hook requests carry no signature, unlike webhooks. Put a secret token in the hook URL, check it on every request, and treat the body as untrusted input.