REST API
Create chatbots, send messages and read analytics from your own backend.
Authentication
Every request needs an API key as a bearer token. Create one in Settings → API keys; it is shown once and stored only as a hash, so we genuinely cannot recover it for you.
Session cookies are deliberately not accepted, which means the API cannot be driven by a cross-site request from a signed-in browser.
curl https://botforge.onzira.com/api/v1/chatbots \
-H "Authorization: Bearer bf_live_…"Scopes
A key carries only the scopes you grant it. Using an endpoint outside a key's scopes returns 403 with the scope it needed.
| Scope | Grants |
|---|---|
| read | List chatbots, conversations and analytics |
| write | Create, update and delete chatbots and knowledge sources |
| chat | Send messages and receive answers |
Endpoints
| Method | Path | Scope | Purpose |
|---|---|---|---|
| GET | /api/v1/chatbots | read | List chatbots, cursor paginated |
| POST | /api/v1/chatbots | write | Create a chatbot |
| GET | /api/v1/chatbots/:id | read | Fetch one chatbot |
| PATCH | /api/v1/chatbots/:id | write | Update settings or publish |
| DELETE | /api/v1/chatbots/:id | write | Delete a chatbot and its data |
| POST | /api/v1/chat | chat | Ask a question |
| GET | /api/v1/conversations | read | List conversations and transcripts |
| GET | /api/v1/analytics | read | Metrics, top sources and content gaps |
Sending a message
Returns the complete answer as JSON. Pass stream: true for Server-Sent Events instead. Either way the exchange is persisted and counts toward your plan exactly as a widget conversation would.
curl https://botforge.onzira.com/api/v1/chat \
-H "Authorization: Bearer bf_live_…" \
-H "Content-Type: application/json" \
-d '{
"chatbot_id": "YOUR_CHATBOT_ID",
"message": "Do you offer refunds on annual plans?"
}'Response
{
"object": "chat_completion",
"conversation_id": "cm…",
"message": {
"id": "cm…",
"role": "assistant",
"content": "Annual plans can be refunded in full within 30 days…",
"citations": [{ "title": "Billing Policy", "url": null, "score": 0.82 }],
"latency_ms": 1240
},
"low_confidence": false,
"usage": { "tokens_in": 812, "tokens_out": 96, "latency_ms": 1240 }
}Streaming
With stream: true the response is text/event-stream with three event types: start carries the conversation id and citations, delta carries each text fragment, and done carries the saved message.
event: start
data: {"conversation_id":"cm…","citations":[…]}
event: delta
data: {"text":"Annual"}
event: done
data: {"message":{…},"low_confidence":false}Pagination
List endpoints are cursor based. Pass limit (max 100) and, to continue, the next_cursor from the previous response. has_more tells you when to stop.
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Body failed validation; `field` names the offender |
| 401 | unauthorized | Missing, malformed or unknown key |
| 401 | key_revoked | The key was revoked |
| 402 | quota_exceeded | Plan limit reached |
| 403 | insufficient_scope | Key lacks the required scope |
| 404 | not_found | No such resource in this workspace |
| 409 | no_knowledge | Publishing a chatbot with nothing indexed |
| 429 | rate_limited | Too many requests; back off |