API Reference
Every public endpoint the widget and your own integrations can call. Requests are JSON, responses are JSON unless the endpoint streams.
Base URL and conventions
All endpoints are served from https://askorac.com/api. Requests with a body send Content-Type: application/json. Timestamps are ISO 8601 UTC. IDs are UUID v4 unless noted.
Two tiers of endpoints exist: widget endpoints (unauthenticated, scoped to a project_id, safe to call from a browser — used by the embedded widget itself) and programmatic endpoints (authenticated with a Bearer API key, available on the Business plan — for server-side integrations).
POST /api/chat — streaming chat
The primary endpoint. Runs the full RAG pipeline (rewriter → hybrid retrieval → re-rank → LLM) and streams the response as Server-Sent Events. Used by the embedded widget; you can also call it directly if you're building a custom UI.
Request body:
{
"project_id": "proj_abc123",
"message": "Does the Pro plan include BYOK?",
"conversation_id": "conv_xyz789",
"page_url": "https://example.com/pricing",
"visitor_id": "visitor_...",
"context": "User is on /pricing. Plan badge visible: Free."
}Only project_id and message are required. conversation_id is omitted on the first message of a new conversation — the server generates one and echoes it back in the first event of the stream.
Response: text/event-stream. Events include conversation_id, token (each streamed content chunk), sources (array of citation URLs), confidence (float 0–1), and a terminal done event. Close the connection on done or on an error event.
GET /api/widget/config
Returns the widget's render-time configuration for a given project — colors, gradient stops, welcome message, position, avatar, branding flags, plan-gated features. Called by the widget on load; typically you won't need to call it yourself.
GET /api/widget/config?id=proj_abc123Response: JSON with name, settings (color, gradient_stops, position, welcome, avatar, show_branding, custom_css), office_hours, and plan_features.
GET /api/widget/messages
Polls for new messages added to a conversation from outside the widget's own session — specifically, human replies from the project owner via the dashboard. The widget calls this every ~20 seconds while open.
GET /api/widget/messages?conversationId=conv_xyz789&since=2026-04-18T11:20:00ZNo auth required — the visitor already owns the conversation ID (generated for them on first open, stored in their own localStorage). Queries are scoped to exactly the conversation ID passed in, so other conversations never leak.
Response:
{
"messages": [
{
"id": "msg_...",
"role": "assistant",
"content": "Hi — responding directly from the team.",
"sources": ["human_reply"],
"created_at": "2026-04-18T11:22:14Z"
}
]
}Omit since to get the full conversation — useful when a visitor reopens the widget after closing it. Merge results with local state by message ID to dedupe.
POST /api/widget/feedback
Records a thumbs-up or thumbs-down rating on an assistant message. Used by the widget's feedback buttons; feeds the Intelligence tab's negative-feedback detection and the Self-Learning Knowledge Loop.
POST /api/widget/feedback
{
"message_id": "msg_...",
"rating": "positive",
"reason": "accurate"
}rating is "positive" or "negative". reason is optional free text, stored verbatim.
POST /api/widget/escalate
Requests a human handoff. Flags the conversation as escalated, optionally captures a visitor email/phone, and fires the new_lead outbound webhook + notification dispatch.
POST /api/widget/escalate
{
"conversation_id": "conv_xyz789",
"email": "visitor@example.com",
"message": "Orac couldn't resolve this — can a human help?"
}email and message are optional. If the visitor explicitly asks for a human in chat, the pipeline detects this upstream via detectHumanRequest and calls this endpoint automatically.
Programmatic API (Business plan)
Business-plan projects get a REST API key that authenticates server-side requests with Authorization: Bearer <key>. Generate and revoke keys from Dashboard → API Keys.
Available endpoints under /api cover account-level operations — listing projects, reading analytics, managing sources, pulling conversation history, creating leads, and configuring custom actions. The full endpoint inventory lives alongside each dashboard tab that exposes the same data; anything visible to you as an owner is also readable over the API.
curl https://askorac.com/api/conversations \
-H "Authorization: Bearer orac_live_..." \
-H "Content-Type: application/json"Rate limit: 60 requests per minute per API key. Responses include X-RateLimit-Remaining and X-RateLimit-Reset headers. Requests over the limit return HTTP 429 with a JSON body describing the retry-after window.
Errors
All endpoints use standard HTTP status codes. JSON error bodies follow a consistent shape:
{
"error": "Project not found",
"code": "project_not_found",
"status": 404
}400 — missing or malformed request body. 401 — missing or invalid API key (programmatic endpoints only). 403 — plan does not permit this operation. 404 — project or conversation not found. 429 — rate limit exceeded. 500 — unhandled server error, logged for investigation. All 5xx errors are retriable; 4xx errors should be fixed client-side before retrying.
Webhooks (outbound)
Orac can POST to a URL you control whenever specific events happen — new conversation started, new lead captured, escalation triggered, negative feedback received, unanswered question detected. Configure in Dashboard → Project Settings → Webhooks. Payloads are signed with HMAC-SHA256; verify using the shared secret shown on the settings page.
Example signature header: X-Orac-Signature: sha256=abc123.... Recompute with your secret over the raw request body and reject mismatches.