API Reference
Widget endpoints (public, unauthenticated)
These are called from inside the widget iframe. They use the Supabase service-role client and bypass RLS by design — see Architecture for why.
POST /api/widget/chat
Streams an assistant response as plain text.
Request body
{
"publicKey": "pk_...",
"visitorId": "client-generated-id",
"message": "How much does a full detail cost?",
"conversationId": "optional, omit to start a new conversation"
}
Response
200— atext/plainstream of the assistant's reply. Thex-conversation-idresponse header carries the conversation ID (new or existing) so the client can pass it on the next message.404— bot not found or inactive429— a rate limit was hit (see Abuse Protection)500— internal error (misconfigured bot, DB failure)
When the owner's credit balance is insufficient, this still returns 200 with a static polite-decline message streamed as the body, not an error status — the widget UI is designed to render it like a normal reply.
GET /api/widget/config/[publicKey]
Returns the bot's visitor-facing branding.
{
"displayName": "Joe's Assistant",
"welcomeMessage": "Hi! How can I help you today?",
"primaryColor": "#0a0a0c"
}
404 if the bot doesn't exist or is inactive.
CRM endpoints (authenticated dashboard users, Phase 9 scaffold)
See CRM Integrations before relying on these — only the OAuth connect flow is implemented; appointment creation is explicitly stubbed.
GET /api/crm/[provider]/connect?botId=...
provider is jobber or housecall_pro. Requires an authenticated dashboard session. Redirects the browser to the provider's OAuth authorize URL, setting short-lived, httpOnly cookies to carry state (CSRF), the target botId, and (for Jobber) a PKCE code verifier through the redirect.
GET /api/crm/[provider]/callback
Handles the OAuth redirect back from the provider, exchanges the authorization code for tokens, and upserts a row into crm_connections keyed on (bot_id, provider). Redirects to /dashboard/bots/[botId]?crm_connected=[provider] on success.
Related
- Embeddable Widget for how the widget page calls these endpoints
- Configuration for the env vars these routes depend on