---
title: "Provision an AI Widget visitor session"
method: POST
path: "/v2/widget/sessions"
tags: ["AI Widget"]
---

# Provision an AI Widget visitor session

`POST /v2/widget/sessions`

## Request

- Base URL: `https://api.chat.ethora.com`
- URL: `https://api.chat.ethora.com/v2/widget/sessions`
- Auth: HTTP bearer

Public, unauthenticated endpoint called by the embedded `ethora-ai-chat-widget`
on mount. Mints (or resumes) an anonymous visitor user in ejabberd, creates a
persistent MUC room, pre-affiliates the visitor and the App's AI bot as members,
and returns the credentials needed for the widget to SASL-bind and join.

Visitor JIDs follow the convention `${appId}_widget-<uuid>` so mod_ethora's
per-app prefix guard accepts them as members of the room. Rooms follow
`${appId}_<roomUuid>` and are tagged in the platform DB as `chats.type='widget'`.

The endpoint is rate-limited per IP (30/minute) since it's reachable from any
browser without auth. It validates that the App exists and has an AI bot
configured before provisioning anything.

## Request body

- object
  - `appId` string, required: The Ethora App _id whose widget the visitor is opening.
  - `resumeXmppUsername` string: Optional resume hint. When supplied, the server reuses the existing visitor identity instead of minting a new one. The widget reads this from localStorage so a returning browser keeps its identity (and its conversation history is reachable to operators by visitor _id). The value MUST start with `${appId}_widget-` or the request 422s.

## Response `200`

```
{
  visitor: {
    xmppUsername: string,   // bare localpart, e.g. "${appId}_widget-<uuid>"
    xmppPassword: string,
    uuid: string,
    jid?: string             // fully-qualified, "<localpart>@<host>"
  },
  room: {
    name: string,           // bare room name, e.g. "${appId}_<roomUuid>"
    chatId: string,         // Mongo _id of the chats row
    jid?: string            // fully-qualified, "<name>@conference.<host>"
  },
  bot: {
    xmppUsername: string,
    jid?: string
  },
  xmpp?: {
    host: string,           // ejabberd host, e.g. "xmpp.example.com"
    service: string,        // MUC service, e.g. "conference.xmpp.example.com"
    wsUrl: string           // canonical WS URL, e.g. "wss://xmpp.example.com/ws"
  }
}
```

## Other responses

- `400`: Bad Request
- `401`: Unauthorized
- `403`: Forbidden
- `404`: App not found. ``` { error: 'App not found', code: 'APP_NOT_FOUND' } ```
- `409`: App has no AI bot configured. ``` { error: 'App has no AI bot configured', code: 'AI_BOT_NOT_CONFIGURED' } ```
- `422`: Validation error (e.g. missing appId, malformed resumeXmppUsername). ``` { error: string, code: 'VALIDATION_ERROR' } ```
- `429`: Rate limit exceeded (default 30 requests / minute / IP). ``` { error: 'Too many requests', code: 'RATE_LIMITED' } ```
- `500`: Internal Server Error
- `502`: Underlying ejabberd registration or room-create call failed. ``` { error: string, code: 'XMPP_REGISTER_FAILED' | 'XMPP_ROOM_CREATE_FAILED' } ```

---

[API](https://skmtc.dev/ethora/apis/platform-api.md) · [All operations](https://skmtc.dev/ethora/apis/platform-api/llms.txt) · [OpenAPI document](https://skmtc.dev/ethora/apis/platform-api/revisions/01b6e64378ee?raw)
