API reference

These are the endpoints the widget itself calls. You won't normally call these directly — the script tag does it for you — but they're documented here for anyone building a custom integration.

No API key in the browser

Your AI provider key never reaches the browser. It's decrypted server-side per request and used only to call the provider — the widget never sees it, and neither does anything you inspect in devtools.

POST /api/qualify

Scores a lead and stores it. Used by the Lead Qualifier widget.

Request
POST /api/qualify
Content-Type: application/json

{
  "widget_id": "a1b2c3d4e5",
  "visitor_name": "Jane Doe",
  "visitor_email": "jane@example.com",
  "visitor_phone": "+1 555 0100",
  "business_type": "E-commerce",
  "monthly_revenue": "$20k–$50k",
  "main_problem": "Losing carts overnight with no follow-up."
}
200 Response
{
  "success": true,
  "score": "Hot",
  "reason": "Confirmed budget and an urgent, well-defined problem.",
  "recommended_action": "Follow up within the hour.",
  "lead_id": 142
}

POST /api/chat

Sends a message and gets a reply. Conversation history is tracked server-side by session_id — the widget generates a random one per page load. Used by the Support Bot widget.

Request
POST /api/chat
Content-Type: application/json

{
  "widget_id": "a1b2c3d4e5",
  "session_id": "sess-a1b2c3d4e5-x7k2p9",
  "message": "Do you ship internationally?"
}
200 Response
{
  "success": true,
  "reply": "Yes — we ship to most countries. Rates are calculated at checkout.",
  "message_count": 4
}

POST /api/process-doc

Uploads a file and returns structured data. Used by the Document Processor widget. The uploaded file is deleted from the server immediately after processing.

Request
POST /api/process-doc
Content-Type: multipart/form-data

document: <file>       (PDF, TXT, DOC, or DOCX, max 10MB)
widget_id: a1b2c3d4e5
200 Response
{
  "success": true,
  "document_id": 88,
  "filename": "invoice-1042.pdf",
  "processing_time_ms": 2140,
  "extracted": {
    "summary": "Invoice for AI widget integration services, $3,000 due.",
    "key_points": ["Net 15 payment terms", "Bank transfer requested"],
    "entities": {
      "names": [], "dates": ["March 3, 2026"],
      "amounts": ["$3,000.00"], "organizations": ["Northwind Traders"]
    },
    "action_items": ["Pay invoice by due date"],
    "document_type": "invoice"
  }
}

GET /api/config/:widgetId

Returns your public widget configuration. Called automatically on page load — no request body, no auth required, and no sensitive fields (like your AI key) are ever included.

200 Response
GET /api/config/:widgetId

{
  "widget_id": "a1b2c3d4e5",
  "widget_type": "support-bot",
  "name": "Acme Co",
  "brand_color": "#0F766E",
  "icon_url": null,
  "font_family": "Inter",
  "widget_position": "bottom-right",
  "border_radius": 12,
  "button_text": "Chat with us",
  "widget_language": "auto",
  "widget_theme": "classic",
  "voice_enabled": 0,
  "hide_branding": false
}

Errors

Every error response follows the same shape.

Error shape
{ "error": "Human-readable message" }

// Validation errors also include:
{ "errors": [{ "msg": "...", "path": "...", "location": "body" }] }
StatusMeaning
400Missing or invalid fields in the request body.
401Missing or expired auth token (dashboard/admin routes only).
403Account suspended, or a permission you don't have.
404widget_id doesn't match an active widget.
422File uploaded but no readable text could be extracted.
429Rate limit exceeded — 100 requests/minute per IP on client routes.
500Something failed server-side. Retry, or check back shortly.
503A dependent service (like the AI provider) isn't configured yet.