API reference
Widget API
The widget API is the public HTTP surface that the embedded widget calls. It's normally invoked automatically by the loader, but you can build custom clients against it for auditing, testing or alternative front-ends.
Endpoints
POST /v1/widget/init
Initializes the widget for a new visitor. No authentication required, but the request's Origin header must match one of the agent's allowed_origins.
Returns: conversation ID, visitor ID, a JWT bearer token, agent configuration, and the last 30 messages if the visitor is resuming an existing conversation.
POST /v1/widget/messages/stream
The primary streaming endpoint. Uses Server-Sent Events to push tokens as the model generates them. Requires the JWT from /init as a bearer token. Optimized for “one-second-to-first-token” latency on the hot path.
POST /v1/widget/messages
Synchronous alternative to the streaming endpoint. Returns the full response in a single JSON payload — easier for non-browser clients but the caller has to wait for the full generation.
POST /v1/widget/leads
Submits a captured lead. JWT-authenticated. Deduplicates on (agent_id, email), updating an existing lead record rather than creating a duplicate.
POST /v1/widget/events
Lightweight telemetry endpoint for client-side analytics — launcher opens, CTA clicks, dismissals, scroll-trigger events.
Authentication & security
Widget tokens are HS256-signed JWTs with a 60-minute expiration. Tokens are conversation-scoped — starting a new conversation requires a fresh /init. CORS is permissive for cross-origin POSTs from any origin that's in the agent's allowed_origins.
Rate limits
Per-endpoint thresholds:
/init— 60 requests/minute per IP./leads— 5 requests/minute per JWT./messagesand/messages/stream— bound by the per-conversation budget rather than a global rate limit./events— 600 requests/minute per JWT.
Rate-limited responses include a Retry-After header so clients can back off correctly.
Note. Origin enforcement is a hard gate on /init. Misconfigured allowed_origins is the most common reason a widget renders locally but fails on the deployed site.