Widget
Public chat and web-call widget endpoints (widget tokens only).
List widget tokens
Section titled “List widget tokens”GET /api-keys/widget
Lists the active widget tokens of one chat agent by fingerprint (prefix and last 4 characters). The token itself can never be retrieved again. Rate limited (30 requests per minute by default).
Scope: agents:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
organisation_id |
query | string | yes | Your organisation ID. Must be the key’s own organisation. |
agent_id |
query | string | yes | The chat agent whose tokens to list. |
Example request
curl -X GET "https://api.foan.ai/api/v1/api-keys/widget" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
{ "success": true, "data": { "keys": [ { "id": "cmf3k2j9x0006abcd1234efgh", "name": "Website widget", "key_prefix": "a1b2c3d4", "last4": "9f3e", "scopes": [ "widget:bootstrap" ], "created_at": "2026-09-20T10:15:30.000Z", "last_used_at": null, "revoked_at": null, "organisation_id": "cmf3k2j9x0001abcd1234efgh", "agent_id": "cmf3k2j9x0005abcd1234efgh", "ai_host": null } ], "total": 1 }}Errors
| Code | When |
|---|---|
| 400 | organisation_id or agent_id missing |
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation |
| 403 | Missing agents:read scope, or organisation_id is not the key’s organisation |
| 429 | Rate limited |
Create a widget token
Section titled “Create a widget token”POST /api-keys/widget
Mints a public widget token (scope widget:bootstrap only) bound to one chat agent, for embedding the chat widget on your website. The key’s owner must be OWNER or ADMIN, the agent must be a CHAT agent in your organisation, and each agent may hold at most 3 active widget tokens. Rate limited (30 requests per minute by default).
Scope: agents:write
Body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
organisation_id |
string | yes | Your organisation ID. Must be the key’s own organisation. Always send it (see notes). |
agent_id |
string | yes | The CHAT agent the token is for. |
name |
string | no | Label for the token. Defaults to “Website widget (<agent_id>)”. |
Example request
curl -X POST "https://api.foan.ai/api/v1/api-keys/widget" \ -H "Authorization: Bearer $FOAN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"organisation_id":"cmf3k2j9x0001abcd1234efgh","agent_id":"cmf3k2j9x0005abcd1234efgh","name":"Website widget"}'Response 201
{ "success": true, "data": { "key": "foan_prod_a1b2c3d4_<32 hex characters>", "id": "cmf3k2j9x0006abcd1234efgh", "name": "Website widget", "key_prefix": "a1b2c3d4", "last4": "9f3e", "scopes": [ "widget:bootstrap" ], "created_at": "2026-09-20T10:15:30.000Z", "last_used_at": null, "revoked_at": null }, "message": "Widget token created. It is public by design and only bootstraps this chat agent. Save it now - you won't be able to see it again."}Errors
| Code | When |
|---|---|
| 400 | scopes was passed, agent_id missing, name shorter than 3 or longer than 255 characters, or the agent is not a CHAT agent |
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation |
| 403 | Missing agents:write scope, organisation_id is not the key’s organisation, or the key’s owner is not OWNER/ADMIN |
| 404 | Agent not found in this organisation |
| 409 | The agent already has 3 active widget tokens; revoke one first |
| 429 | Rate limited (body is {success:false, message}) |
Revoke a widget token
Section titled “Revoke a widget token”POST /api-keys/widget/revoke
Revokes one widget token of one chat agent. Only bootstrap-only tokens bound to the named agent can be revoked here; management keys are refused. Any member role may revoke. Rate limited (30 requests per minute by default).
Scope: agents:write
Body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
organisation_id |
string | yes | Your organisation ID. Must be the key’s own organisation. |
agent_id |
string | yes | The chat agent the token belongs to. |
key_id |
string | yes | ID of the widget token (from the list endpoint). |
Example request
curl -X POST "https://api.foan.ai/api/v1/api-keys/widget/revoke" \ -H "Authorization: Bearer $FOAN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"organisation_id":"cmf3k2j9x0001abcd1234efgh","agent_id":"cmf3k2j9x0005abcd1234efgh","key_id":"cmf3k2j9x0006abcd1234efgh"}'Response 200
{ "success": true, "data": { "id": "cmf3k2j9x0006abcd1234efgh", "name": "Website widget", "key_prefix": "a1b2c3d4", "last4": "9f3e", "scopes": [ "widget:bootstrap" ], "created_at": "2026-09-20T10:15:30.000Z", "last_used_at": null, "revoked_at": "2026-09-20T10:15:30.000Z", "organisation_id": "cmf3k2j9x0001abcd1234efgh", "agent_id": "cmf3k2j9x0005abcd1234efgh", "ai_host": null }, "message": "Widget token revoked. The chat widget will stop loading on any page that still uses it."}Errors
| Code | When |
|---|---|
| 400 | organisation_id, agent_id or key_id missing, or the token is already revoked |
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation |
| 403 | Missing agents:write scope, or organisation_id is not the key’s organisation |
| 404 | No widget token with that id belongs to this agent (also returned for keys in other organisations and non-widget keys) |
| 429 | Rate limited |
Bootstrap the chat widget
Section titled “Bootstrap the chat widget”POST /widget/bootstrap
Returns the configuration the embedded chat widget needs for one CHAT agent in the key’s organisation. When roomName is sent it also opens a chat session (if one with that room name does not exist yet) and returns a 1-hour session token. A token bound to an agent only works for that agent. Rate limited (30 requests per minute by default).
Scope: widget:bootstrap
Body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
agentId |
string | yes | The CHAT agent to load. |
participantName |
string | no | Visitor’s name. Required when roomName is sent. |
phoneNumber |
string | no | Visitor’s phone number. Required when roomName is sent. |
roomName |
string | no | Conversation ID to open or resume a chat session under. |
customVariables |
object | no | Values merged over the agent’s default custom variables. |
Example request
curl -X POST "https://api.foan.ai/api/v1/widget/bootstrap" \ -H "Authorization: Bearer $FOAN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"agentId":"cmf3k2j9x0005abcd1234efgh","participantName":"Priya Sharma","phoneNumber":"+919876543210","roomName":"chat-7f3a9c2e","customVariables":{"orderId":"A1042"}}'Response 200
{ "success": true, "message": "Widget bootstrap successful", "data": { "metadata": { "orgId": "cmf3k2j9x0001abcd1234efgh", "agentId": "cmf3k2j9x0005abcd1234efgh", "agentName": "Order confirmation", "agentIdentity": "You are Nina, a friendly assistant for Sharma Foods.", "agentTask": "Help visitors check order status.", "agentPersonality": "Warm and concise.", "pronunciation": "", "escalationMessage": "", "greetingMessage": "Hi, how can I help you today?", "closingMessage": "Thank you for chatting with us.", "voicemailMessage": "", "agentLanguage": "en", "callType": "chat", "callDirection": "INBOUND", "channel": "widget", "participantName": "Priya Sharma", "phone_number": "+919876543210", "customVariables": { "orderId": "A1042", "participantName": "Priya Sharma", "phoneNumber": "+919876543210" }, "functionTools": {}, "roomName": "chat-7f3a9c2e", "agentToken": "<1-hour session token>", "webCallEnabled": true } }}Errors
| Code | When |
|---|---|
| 400 | agentId missing, agent is not a CHAT agent, or roomName sent without participantName and phoneNumber |
| 401 | Missing, invalid or revoked key (API keys only) |
| 403 | Missing widget:bootstrap scope, agent belongs to another organisation, or the token is bound to a different agent |
| 404 | Agent not found |
| 429 | Rate limited |
| 500 | Any other failure (errors are not mapped to specific statuses) |
Start a browser voice call
Section titled “Start a browser voice call”POST /widget/voice-session
Starts a billable in-browser voice call with a CHAT agent that has web calling enabled, and returns the room credentials for the browser. Each phone number (8 or more characters) may start 3 calls per organisation per 24 hours, and each IP address 10 when no number is given. Rate limited (30 requests per minute by default). The call is charged to the organisation’s wallet; a refusal for money is a 402 so the page can tell the visitor to try later rather than treating it as a crash.
Scope: widget:bootstrap
Body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
agentId |
string | yes | The CHAT agent to talk to. |
participantName |
string | no | |
participantNumber |
string | no | Visitor’s phone number. Used for the per-number call cap and returning-caller memory. |
roomName |
string | no | Accepted but currently has no effect. |
customVariables |
object | no | Values merged over the agent’s default custom variables. |
Example request
curl -X POST "https://api.foan.ai/api/v1/widget/voice-session" \ -H "Authorization: Bearer $FOAN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"agentId":"cmf3k2j9x0005abcd1234efgh","participantName":"Priya Sharma","participantNumber":"+919876543210"}'Response 200
{ "success": true, "message": "Web call session created", "data": { "success": true, "callType": "web", "roomName": "cmf3k2j9x0005abcd1234efgh_919876543210_1758363330000", "sessionId": "66f1c2e8a4b5c6d7e8f90123", "token": "<participant token>", "wsUrl": "wss://realtime.example.com" }}Errors
| Code | When |
|---|---|
| 400 | agentId missing, agent is not a CHAT agent, web calling is not enabled for the agent, or the agent is not active |
| 401 | Missing, invalid or revoked key (API keys only) |
| 402 | The organisation cannot pay for the call: wallet balance too low, account suspended, or the plan’s call limit reached |
| 403 | Missing widget:bootstrap scope, agent belongs to another organisation, or the token is bound to a different agent |
| 404 | Agent not found |
| 409 | The same call was requested again within a few seconds (same agent, visitor number and key owner) and is already being set up |
| 429 | Per-number/IP call cap reached, or rate limited |
| 500 | Any other unexpected failure |
| 503 | The realtime voice server is unavailable, or the Muncho wallet could not be checked; try again shortly |

