Docs/Reference/Widget API

Widget API

The widget API is a small set of endpoints under https://api.neofir.com/v1/widget/*. Auth is an X-Api-Key header carrying your org's widget key. Origin enforcement runs server-side against your allowed_domains list.

POST /widget/init

Resume or create a conversation; receive the org config.

POST /v1/widget/init
X-Api-Key: pk_live_...
Content-Type: application/json

{
  "visitor_id": "uuid-or-null"
}

Response:

{
  "org": {
    "name": "Neofir",
    "branding": {
      "primary_color": "#a47d52",
      "welcome_msg": "Salut. Neofir...",
      "logo_url": null
    },
    "shortcuts": ["Prețuri", "Cum funcționează", "Integrări", "Discovery call"]
  },
  "conversation_id": "uuid",
  "visitor_id": "uuid"
}

Rate limit: 10 / 5 min per IP.

POST /widget/message

Send a user message; receive a streamed reply.

POST /v1/widget/message
X-Api-Key: pk_live_...
Content-Type: application/json

{
  "conversation_id": "uuid",
  "visitor_id": "uuid",
  "content": "How much does Studio cost?"
}

Response: Server-Sent Events. Each event is data: {...}\n\n.

data: {"type":"delta","content":"Studio is €45"}
data: {"type":"delta","content":"/month..."}
data: {"type":"final","content":"Studio is €45/month, 2,000 messages, all channels.","chips":["Pornim?"],"message_id":"uuid"}

Possible event types:

Rate limits: 30 / min per visitor_id, 20 / min per org.

POST /widget/feedback

Record thumbs-up / thumbs-down on a message.

POST /v1/widget/feedback
X-Api-Key: pk_live_...

{
  "message_id": "uuid",
  "rating": "up" | "down",
  "reason": "string optional"
}

GET /widget/availability

Returns the next N available slots for a given service id. Used by the inline slot picker; the agent also calls this internally via check_availability.

GET /v1/widget/availability?service_id=demo&from=2026-06-01&to=2026-06-07
X-Api-Key: pk_live_...

POST /widget/booking

Confirm a booking once the agent has gathered name, phone, slot, service.

POST /v1/widget/booking
X-Api-Key: pk_live_...

{
  "conversation_id": "uuid",
  "service_id": "demo",
  "starts_at": "2026-06-02T10:00:00Z",
  "customer_name": "Leo",
  "customer_phone": "+40751051221",
  "customer_email": "leo@example.com"
}

Error codes

CodeHTTPMeaning
VALIDATION_ERROR422Body did not match the Zod schema.
RATE_LIMIT429You hit one of the rate windows. Retry after the Retry-After header.
QUOTA_EXCEEDED402The org has used its monthly message quota.
UNAUTHORIZED401Missing or invalid X-Api-Key.
ORIGIN_NOT_ALLOWED403The request's Origin is not in the org's allowed_domains.
NOT_FOUND404Conversation, service, or booking not found in this org.
BOOKING_FAILED409Slot taken, outside hours, or constraint violation.
INTERNAL500Backend failure. Logged with a request id you can quote in support.