Widget Service Protocol
The first-stage integration uses a short-lived server-issued Widget Session. Never expose an Open4X API key in browser code.
Staging
API: https://open4x-gateway-staging.29498587.workers.dev
Widget: https://open4x-widget-staging.pages.dev/widget.js
Version: loader 1.1.0 / runtime 2.3.0Create a session server-side with bot:session:create:
curl -X POST "$OPEN4X_BASE/v1/apps/bot/widget/auth" \
-H "X-API-Key: $OPEN4X_BRIDGE_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"external_user_id":"knv-anon-001","user_name":"Alice","ttl_seconds":1800}'TTL is 900–3600 seconds, defaulting to 1800. Pass only the returned session_token to the browser.
<script
src="https://open4x-widget-staging.pages.dev/widget.js"
data-token="SERVER_ISSUED_SESSION_TOKEN"
data-gateway-url="https://open4x-gateway-staging.29498587.workers.dev">
</script>Messages and reconnect
GET /v1/apps/bot/widget/messages
POST /v1/apps/bot/widget/send
GET /v1/apps/bot/widget/ws?token=<session_token>
GET /v1/apps/bot/widget/events?cursor=<cursor>&limit=100Send a stable client_message_id for idempotency. A replay returns the original message_id. Text is limited to 8,000 Unicode characters, the Widget HTTP route defaults to 15 requests/minute (other /v1/apps/* routes are typically 60 requests/minute), and each chat allows four active WebSocket connections. Reconnects must backfill through /messages or /events. Revoked or expired sessions close with code 4001 and must not reconnect forever.
The server-side bridge should use the tenant-wide aggregate feed GET /v1/apps/bot/widget/events?limit=100&cursor=... instead of polling each chat_id. Non-empty pages consume the independent event_daily_quota; empty pages do not, while the per-minute rate limit still applies. The current staging Bridge Key allows 10,000 non-empty event pages per UTC day; production limits are defined by the signed commercial contract.
Incremental events
The event feed requires bot:events:read and returns stable event_id, conversation_id, chat_id, message_id, client_message_id, direction, visibility, creation time, and an opaque cursor. Save the cursor only after the event is committed to the Knoveria outbox. Replaying a cursor is safe.
X-Open4X-Event-Timestamp: <unix_seconds>
X-Open4X-Event-Signature: sha256=<hex>The staging v1 signing input is <timestamp>.<raw_response_body> using HMAC-SHA256 and the current API key as the signing key. Production must switch to a dedicated event secret before the commercial contract is frozen.
The repository file docs/commercial/WIDGET_SERVICE.md is the full contract for retry, CSP/CORS, self-hosting, and boundary details.