API Documentation
UI widgets: developer reference
The widget definition (.widget) format, the node tree, function objects, the endpoint contract for call_api, error codes and security rules.
๐งฐ UI widgets: developer reference
This page describes the stored format of a widget, how its functions talk to your API, and the error contract. The user-facing guide lives under UI widgets.
๐ฆ Widget definition
A .widget file and the API object share the same shape:
{
"uuid": "โฆ",
"name": "Order status",
"description": "Shows the status of an order",
"category": "ecommerce",
"tree": { "type": "Card", "children": [] },
"schema": { "type": "object", "properties": {} },
"defaultState": {},
"examples": [{ "name": "Example 1", "state": {} }],
"states": [],
"functions": []
}category:booking|ecommerce|forms|analytics|other.treeโ a single root node; the JSX view is printed from it.schemaโ a JSON Schema subset:type,properties,items,required,enum,default,format,description.
๐ฒ The node tree
Every node is an object with a type; children live in children:
{
"type": "Card",
"gap": 3,
"children": [
{ "type": "Title", "value": "{{order.title}}", "size": "lg" },
{ "type": "Badge", "label": "{{order.status}}", "color": "info" },
{
"type": "Repeat",
"each": "{{order.items}}",
"as": "item",
"children": [{ "type": "Text", "value": "{{item.name}}" }]
}
]
}- A binding is a path in double curly braces. A prop that is exactly one binding keeps the bound value's type.
Repeatiterates an array (each,as); the item index is exposed as<as>Index.Statelinks to a visibility rule byname.
โ๏ธ Function objects
{ "name": "confirm", "type": "call_api",
"url": "https://api.example.com/book",
"method": "POST",
"headers": { "Authorization": "Bearer โฆ" },
"inputs": { "id": "{{order.id}}", "note": "{{note}}" },
"additionalInputs": ["note"],
"onSuccess": { "type": "set_variables", "variables": { "booked": true } },
"onFailure": { "type": "set_variables", "variables": { "error": "โฆ" } } }Other types: set_variables (variables), send_message (message, hidden), open_link (url), dismiss.
๐ How call_api is executed
- When a widget is delivered into a conversation, a
call_apifunction loses itsurl,method,headersandinputs, and is marked as proxied. - The browser sends only the function name and the inputs; the server performs the request against your endpoint.
- The server resolves tokens against the state stored with the message, overlaid with the accepted inputs.
inputsis a whitelist: keys not declared in the function'sadditionalInputsare dropped.
๐ The visitor-side call
POST /api/v1/widget/ui-widget/{widget_uuid}/functions/execute
{
"message_uuid": "โฆ",
"function_name": "confirm",
"inputs": { "note": "hi" },
"tool_call_id": "call_1"
}- Authorized with the chat widget's own token.
message_uuidis required: it proves the visitor was shown this widget. State and session are read server-side and never accepted from the browser.tool_call_iddisambiguates a message that rendered the same widget twice.
๐จ Errors
{ "success": false, "error": { "code": "โฆ", "message": "โฆ" } }WIDGET_FUNCTION_NOT_CALLABLEโ the visitor may not call this function.WIDGET_INVALID_TOKEN,NOT_A_WIDGET_VISITORโ token problems.WIDGET_NOT_IN_MESSAGEโ no message rendered this widget.WIDGET_FUNCTION_NOT_FOUND,WIDGET_FUNCTION_FAILED,WIDGET_FUNCTION_UNAVAILABLE.429โ rate limit (60 requests per minute per IP).- A
200withok: falsemeans your own API refused the request.
๐ค What your endpoint should return
- A JSON object. With
waitForResponsethe response is merged into the widget data and bindings re-render. - Return the field names from the schema, or use the
Call API + show widgetaction with a response mapping:{ "orders": "data.items" }. - There is no idempotency key โ guard repeated calls on your side. The browser blocks a parallel call of the same function, but network retries are still possible.
๐งพ Limits
- Only whitelisted components may appear in the tree; anything else is rejected.
- Widgets are project-scoped: a widget from another project is not found.
- The
Mapcomponent and the iframe-based client function are not supported yet.