Support assistant
The chat in the corner of the Driftstack website, the docs and the dashboard. It is an AI that answers questions about Driftstack from these docs and, when you are signed in, from a few facts about your own account (your plan, your trial end, your plan’s limits and why your recent sessions failed). Its answers are not reviewed by a person. You can ask for a person at any time; that turns the conversation into a support ticket.
These routes serve the Driftstack widget. They are not part of the published API for your programs: an API key or an OAuth token is refused (403). A visitor who is not signed in uses them without credentials, behind a browser check; a signed-in customer uses them with the dashboard’s session or the desktop app’s sign-in.
Routes
| Route | Who | What it does |
|---|---|---|
GET /v1/support/assistant/status |
anyone | Whether the assistant is available to you, the Turnstile site key when visitors may use it, and the limits. |
POST /v1/support/assistant/conversations |
anyone | Starts a conversation. A visitor sends a Turnstile token (action assistant_start). Returns conversation_id, conversation_token (once) and expires_at. |
POST /v1/support/assistant/conversations/{id}/messages |
the conversation’s caller | Asks a question: {"text": "…"}, and optionally where you are asking from (context, below). Requires Idempotency-Key. |
POST /v1/support/assistant/conversations/{id}/handoff |
the conversation’s caller | Hands the conversation to a person. Signed in, it needs the write scope. |
POST …/conversations/{id}/turns/{turnId}/feedback |
the conversation’s caller | “Did this help?” for one reply: {"helpful": false, "comment": "…"}. One rating per turn; a second one replaces it. |
Send conversation_token back in the x-driftstack-conversation-token
header on every message and on the hand-off. It is the only proof that a
conversation is yours; never put it in a URL. Without the right token — or,
when you are signed in, from another account — every conversation answers 404. A conversation expires after two idle hours.
A message and its reply
{
"turn_id": "sat_3f2c9d1e-7b4a-4c1d-9e8f-2a6b5c4d3e1f",
"reply": {
"text": "Start a session from the dashboard, or call POST /v1/sessions.",
"sources": [
{
"title": "Sessions — Starting a session",
"url": "https://docs.driftstack.io/guides/sessions"
}
]
},
"handoff_suggested": false,
"blocked": null,
"remaining_turns": 11
}
reply.text is plain text: show it as text, never as HTML or Markdown.
The only links are sources, and each is a Driftstack docs or legal page the
answer cited. A conversation holds up to 12 messages of up to 1,500
characters. Send the same Idempotency-Key when you retry a message: the
retry is answered from the stored reply (see
Idempotency keys for how keys work elsewhere).
Where you are asking from
In the dashboard and the desktop app, a message can also say where the question was asked, so a short question is read the way it was meant:
{
"text": "…",
"context": { "screen": "dashboard.api_keys" }
}
screenis a fixed name: a dashboard page (dashboard.overview,dashboard.api_keys,dashboard.webhooks,dashboard.usage,dashboard.billing,dashboard.audit_log,dashboard.team,dashboard.security,dashboard.credentials,dashboard.settings,dashboard.help) or the desktop app screen Help was opened from (app.home,app.get_started,app.ai,app.recipes,app.profiles,app.proxies,app.sessions,app.sessions_history,app.recordings,app.connectivity,app.servers,app.team,app.billing,app.settings,app.help).error_codeis the error you are seeing, when Help was opened from one: a three-digit HTTP status (426), or the code a stopped session reports (proxy_required,DriverError). One token of at most 48 characters. A code the assistant does not know is ignored, and the message is answered without it.
Both are optional. They are labels, never a URL, the page’s content, a value
you typed or anything personal: any other key in context is refused with a 400. A screen counts only where it belongs (a dashboard.* name from the
dashboard, an app.* one from the desktop app) and is ignored otherwise, as
is a name not on the list above. The assistant uses them to read your question and to
choose the docs it answers from, and they are kept with the conversation as
those two labels.
On the website and in these docs, the chat sends the page you are reading
instead, as page: the site and the path, such as website:/pricing/ or
docs:/quickstart/ — never the query, the fragment or anything on the page:
{
"text": "how much is it?",
"context": { "page": "website:/pricing/" }
}
A page counts when it is one the assistant can answer from (a docs page, a legal page or an indexed website page) or a home page, and only from the website or the docs; any other page is ignored. The assistant reads it as the page’s title, uses it like a screen, and does not keep it.
turn_id names the turn the reply became, for Did this help?
below. It is null when a refusal consumed no turn (too_long, turn_limit,
rate_limited, disabled): there is nothing to rate.
When there is no answer, blocked.reason says why:
blocked.reason |
Meaning |
|---|---|
off_topic |
Not a question about Driftstack, or something the assistant does not do. |
acceptable_use |
Asks for help with something the Acceptable Use Policy forbids. |
d9_handoff |
A security, privacy, legal or abuse report. No AI reads these: hand it to a person. |
rate_limited |
Too many messages just now. |
cap_reached |
The assistant is unavailable for now. |
too_long |
Over 1,500 characters. |
turn_limit |
The conversation reached 12 messages. |
disabled |
The assistant is switched off. |
acceptable_use is about what a message asks the assistant to help do — for
example credential stuffing, fraud or attacking a website — as the
Acceptable Use Policy defines it. Questions
about what Driftstack does and how to use it are answered, including running
many profiles, automation, collecting public data and how websites see a
session.
Did this help?
POST /v1/support/assistant/conversations/{id}/turns/{turnId}/feedback
The widget asks after every reply. Send {"helpful": true} or
{"helpful": false, "comment": "…"} with the conversation token, exactly as
you send a message; turnId is the reply’s turn_id. No Idempotency-Key is
needed: there is one rating per turn, and a second submission for the same
turn replaces the first — a thumbs-down followed by a comment is one rating.
The comment is optional, at most 500 characters, and is stored with
recognised credentials removed; it is never returned. The response is
{"turn_id": "sat_…", "helpful": false}. A turn that is not this
conversation’s, like a wrong token, answers 404.
What you say goes to the people who write these docs: replies customers say did not help are listed for them by the pages the reply cited, so a wrong or missing page gets fixed.
Talking to a person
POST …/handoff with {"include_transcript": true, "message": "…"}.
- Signed in: it becomes a conversation under Help, where the reply arrives. At most 3 open conversations and 5 new ones an hour, as in Help.
- Not signed in: also send
email(where a person may reply) and a fresh Turnstile token (actionassistant_handoff). The address is not verified: nothing is emailed to it automatically and nothing is linked to an account. - A report (security, privacy, legal or abuse) goes to a restricted
Driftstack mailbox (
owner_only_mailbox), andrequest_refis the reference to quote.
The response is {"ticket_id": "sth_…", "delivered_to": "support" | "owner_only_mailbox", "request_ref"?: "…"}.
With include_transcript, the server attaches the conversation as it stored
it — recognised credentials removed — labelled as an AI transcript.
What the assistant never does
It has no tools and takes no action: it cannot refund, cancel, delete or change anything, and it says so. It does not know API keys, payment details, proxy credentials or anything about another account. Recognised credentials you paste are removed before your message is stored or sent to the model (Anthropic). Conversations are kept 90 days, or with the support ticket after a hand-off.