A published assistant answers your customers from its workspace's sources, through one endpoint you can call from your own site or any HTTP client. Every answer lists the sources it cites. Calls spend your own model key, so every key has a daily cap. It answers with the published version's prompt, tone, refusal and handoff message, the same instructions a test chat on that version uses.
The public key
Each published assistant can have public keys (prefix flk_pub_). A
public key reaches this endpoint and nothing else: it is not an organization API
key, and every other /api/v1 route refuses it. Anyone who sees your
site's source can read the key, so treat it as public and rely on its limits:
- a daily cap (200 calls by default), counted per assistant per UTC day across every node before the model is called;
- a per-visitor daily token budget and a short per-visitor rate limit;
-
an optional list of allowed sites. It is advisory: it stops
casual copying of your snippet, but any non-browser client can send whatever
Originit likes. The cap and revoking the key are the real controls.
Ask a question
$ curl -N https://flickercloud.com/api/v1/assistants/$ASSISTANT_ID/chat \ -H "Authorization: Bearer $FLICKER_PUBLIC_KEY" \ -H "Content-Type: application/json" \ -d '{"message": "How do returns work?"}'
The key may also travel in an X-Assistant-Key
header. A message
is at most 2000 characters and 7 KB, and the whole request body at most 16 KB. Browsers may call the endpoint
directly: it answers the CORS preflight for any origin and never accepts cookies.
The website widget
To put the assistant on a site without writing code, add one script tag with your
assistant's id and a public key. It adds a chat bubble (a bottom sheet on a phone)
that shows your starter questions, streams a quiet progress line, and answers with
its sources. It runs in a shadow root so your page's CSS cannot break it, sets no
cookies, loads nothing from third parties, and keeps only the conversation id, in sessionStorage.
<script src="https://flickercloud.com/widget.js" data-key="flk_pub_..." data-assistant="ID" async></script>
Optional attributes: data-accent
(a hex colour), data-position="left", and data-title
(defaults to the assistant's name). The script talks only to the origin it was
loaded from.
If your site sends a Content-Security-Policy, allow this much and
nothing more:
script-src https://flickercloud.com connect-src https://flickercloud.com
The widget injects its own styles into its shadow root, so a policy that forbids
inline styles also needs style-src 'unsafe-inline'
or the widget will render unstyled. To try it before you embed it, open
/widget/test?key=flk_pub_...&assistant=ID
on this site. The widget reads GET /api/v1/assistants/:id
(same key; returns the name and starter questions of the published version) and
then uses the chat endpoint below. Everything under The public key
applies:
the daily cap, the visitor limits and the advisory site list.
The streamed reply
Once the assistant starts working the reply is 200
with text/event-stream: one step
event per pipeline step as it finishes (its name only), then one answer
event.
event: step data: {"step":"search"} event: answer data: {"answer":"Returns are accepted within 30 days [1].","citations":[{"position":1,"title":"Returns policy","url":null,"snippet":"..."}],"conversation_id":"..."}
The answer text arrives whole in the answer
event, not word by word. Its [n]
markers point at citations
by position. If the assistant fails after streaming began, the last
event is error
with the same error
and message
fields as below. Lines starting with :
are keep-alives; ignore them.
Conversations
Send the conversation_id
from an answer with the next message to continue that conversation. The id is opaque
and only works with the key that started it. A conversation holds up to 20 questions, one at a time; after that, start a new one. Each
question is answered from your sources on its own: earlier turns are stored for
you, not sent to the model.
A conversation id belongs to the key that started it. After you rotate or revoke
that key, or after Flicker rotates its own signing secret, the old id answers 404 conversation_not_found: drop it and start a new conversation by
sending the next message without one.
Visitors' conversations are third-party text. Each assistant keeps them for its retention setting (30 days by default, at most 365) and they are deleted daily after that.
Errors
A request refused before the assistant runs gets a JSON body
{"error": code, "message": text}
and no key or internal id:
-
401 unauthorized: missing, revoked or expired key (one answer for all). -
403 origin_not_allowed: the key's allowed-sites list refused the Origin. -
404 not_found/conversation_not_found: not this key's assistant, not published, or an unknown conversation. 409 conversation_busy: the conversation is still answering.-
413 too_large,422 invalid_message,message_too_long,conversation_too_long. -
429 rate_limited,visitor_limit_reached,daily_cap_reached, each with aRetry-Afterheader in seconds (the last two: until midnight UTC). 502 unavailable,504 timeout.
A call refused by the daily cap costs nothing. A call that reached the model counts against the cap even if the model then fails, so an outage cannot become free retries.