Skip to content
TriedDocs
Public endpoints

Public endpoints overview

Endpoints a browser calls with a public key, a chat token, a share token or a signed link instead of a secret API key.

Public endpoints are the routes under /public/ plus GET /widget.js. They are made to be called from a web page or opened as a link, so they never take a secret API key. Each one is authorised by something that is safe to expose for its purpose:

Credential Where it comes from Endpoints
Public key plus an allowed Origin Public keys Start widget chat
Chat token Returned by Start widget chat Send widget chat message, End widget chat
Share token Create share link Get share link, Share link chat, Share link web call
Signed link (exp and sig) Fields on the call object and asset object Get public call log, Get public KB retrievals, Get public asset
None Widget script

Public endpoints or a secret key#

Use a secret API key (key_...) from your own servers. It reaches every route its scopes allow, so it must never appear in a web page, an app bundle or a URL.

Use public endpoints when code runs in a visitor's browser or a link is handed to someone outside your workspace:

  • The chat widget and your own chat UI on a website use a public key.
  • A Voice Orb page uses a share token. See Share a Voice Orb link.
  • public_log_url and knowledge_base_retrieved_contents_url on a call, and url on an asset, are signed links you can open or pass on without a key.

A public key also works as Authorization: Bearer public_key_... on POST /v3/create-web-call, /create-chat, /create-chat-completion and /end-chat/{chat_id}, from an allowed Origin. Those routes are documented with the rest of the API; see Authentication. Every other authenticated route returns 403 (A public key can only start web calls and chats).

Public key checks#

Start widget chat, and the four authenticated routes above when called with a public key, check the request in this order:

  1. Origin. The Origin header must match one of the key's allowed_domains. *.example.com matches any subdomain and example.com itself. An entry with a port only matches that port; an entry without one matches any port. A request without Origin is refused, so a public key does not work from server code or cURL. Start widget chat answers a bad Origin with 403 (Origin <origin> is not allowed for this key); the authenticated routes treat the key as invalid and answer 401.
  2. Blocked countries. The country is read from cf-ipcountry, x-vercel-ip-country or x-country-code, in that order. When it is in the key's blocked_countries the request gets 403 (Requests from <country> are blocked for this key). With none of those headers the check is skipped.
  3. Per-IP limit. 30 requests per minute from one IP on one key (PUBLIC_KEY_IP_RATE_PER_MINUTE on the API). Over it: 429 (Too many requests from this address. Retry in <s>s.).
  4. Key limit. When the key has rate_limit_per_minute, all requests on the key share that limit. Over it: 429 (This public key is over its limit of <n> requests per minute.).
  5. reCAPTCHA. When the key has recaptcha_enabled, the reCAPTCHA v3 token is read from recaptcha_token in the body, or from the x-recaptcha-token header. A missing token, a failed check or a score below recaptcha_threshold returns 403 (reCAPTCHA check failed (score <s> below <threshold>)).
  6. Credit. Start widget chat, create web call, create chat and create chat completion return 402 when the workspace is out of credit or over its monthly budget. The authenticated routes also return 402 when an invoice is overdue.
Needs keys

Real reCAPTCHA verification needs RECAPTCHA_SECRET on the API. Without it, verification is mocked: a missing token scores 0, a token of the form mock:<score> scores that value, and any other token scores 0.9.

Rate limits#

Every public endpoint counts toward the per-IP limit that applies to all routes: 3000 requests per minute by default (RATE_LIMIT_PER_IP). Over it, the API returns 429 with Rate limit exceeded for this IP address. The public key limits above apply on top. Share token and signed link endpoints have no other limit. See Rate limits.

CORS#

Routes under /public/ and /widget.js accept requests from any origin for GET, POST and OPTIONS. They do not use the dashboard session cookie. The Origin allowlist is enforced by the public key itself, not by CORS.

Errors#

Public endpoints use the same error body as the rest of the API.