probot-self-hosted widget only talks to the ProBot platform when
you supply a dashboard.token. And even then, only two write-only
endpoints under /api/v1/bot/*.
Both are authenticated with the pbt_… bot token minted in your
dashboard:
- A missing or malformed header →
401 missing_bot_token. - An unknown, revoked, or expired token →
401 invalid_bot_token. - The token resolves to exactly one bot, so no
botIdis ever passed in a request body or path parameter.
This contract is pinned to v1. Breaking changes will ship as
/api/v2 with a documented deprecation window, so a deployed widget or
server-side client can rely on a stable shape.Base URL
Production:dashboard.apiUrl on <ProbotBot />, or by
overriding your custom SDK’s base URL. Useful for staging mirrors or when
running the platform locally for tests.
Endpoints
POST /api/v1/bot/conversations
Persists one chat session’s transcript so it appears in the owner’s
dashboard. UPSERTs on (bot, sessionId), so the same sessionId sent
twice coalesces into one conversation row and the message count
increments.
Request:
Success response (
201 Created):
curl:
- Emits a
conversation_startednotification (once, on first insert) visible in the owner’s dashboard bell. - Bumps the bot’s aggregate
total_conversationsandtotal_messagescounters (surfaced on the dashboard overview).
POST /api/v1/bot/leads
Captures a recruiter lead. Idempotent on (bot, conversationId, email) -
a duplicate submission returns 200 with deduped: true instead of
creating a second row.
Request:
Fresh capture response (
201 Created):
200 OK):
lead.id in the deduped response is the ORIGINAL row’s id, not a
newly-minted one. That lets a client optimistically build “leads I’ve
touched” state without knowing whether the platform had the row before.
Failure responses:
curl:
- Emits a
lead_capturednotification. - If the bot owner has
notify_leads_emailenabled, best-effort sends an email to their account address.
Rate limits
Both endpoints are rate-limited per bot via the same underlying rate limiter used for the managed/api/chat/[botId] path:
- Default 10 requests / minute per bot.
- Default 50 requests / day per bot.
- Overrideable per-bot via the dashboard’s Bot Configuration → Advanced → Rate limits.
- On rejection:
429 rate_limitedwith aRetry-Afterheader.
What’s not exposed
Deliberately absent from this contract:GET /config- self-hosted bots configure themselves in your codebase, so there is no platform-sideconfigendpoint. The widget never reads config from us.POST /knowledge- knowledge lives in your<ProbotBot />props. No retrieval-as-a-service call.PUT/PATCH/DELETEon conversations or leads - the contract is write-only. Data mutations happen through the owner’s dashboard, not the token surface.
Debugging tips
Confirm your token works before wiring the widget:401, the token is wrong or revoked. Double-check the
dashboard’s Token list.
Watch analytics land in real-time: register a bot, mint a token, then
in one terminal send a conversation POST, and in another watch the
dashboard - the row shows up within a couple of seconds.
Client SDK
If you’d rather not hand-roll the fetch calls,probot-self-hosted
ships helpers:
null / false - matching the
widget’s “analytics never breaks chat” contract. Wrap with your own
try/catch if you want to surface failures to the caller.