Quickstart
You will provision a chat tenant, retrieve its three credentials
(tenant_id, tenant_secret, widget_public_key), embed the widget on
your page, then make a signed backend call to the relay.
Step 1 — Provision a tenant
Section titled “Step 1 — Provision a tenant”Only tenant_name is required; every other field has a default. The
response contains tenant_id, tenant_secret and widget_public_key
only once.
curl $BASE_URL/api/v1/provision/tenant \ -X POST \ -H "X-Admin-Key: YOUR_ADMIN_KEY" \ -H "Content-Type: application/json" \ -d '{ "tenant_name": "Demo Boutique", "allowed_origins": ["https://shop.demo.com", "app://bloonio_chat_flutter"] }'The operations script bash/seeds/provision-tenant.py wraps the same call
(stdlib only, secrets printed once):
python3 bash/seeds/provision-tenant.py \ --relay-url $BASE_URL \ --admin-key "$ADMIN_API_KEY" \ --tenant-name "Demo Boutique" \ --origin https://shop.demo.com \ --origin app://bloonio_chat_flutterIt prints, ready to paste, the backend environment variables (HMAC#1) and those for the widget / in-app SDK.
Response (201) — the data envelope contains:
{ "status_code": 201, "data": { "tenant_id": "019e4ae7-1a2b-7c3d-8e4f-5a6b7c8d9e0f", "tenant_secret": "sk_...", "widget_public_key": "pk_...", "tenant_name": "Demo Boutique", "rate_limit_per_min": 60, "created_at": "2026-06-21T10:00:00Z" }, "message": "Tenant provisioned. Save tenant_secret and widget_public_key now — the secret will not be shown again."}Step 2 — Capture the credentials
Section titled “Step 2 — Capture the credentials”Store the values where they are used — two distinct surfaces:
# Tenant backend (HMAC#1, e.g. your service's .env.*)CHAT_RELAY_BASE_URL=$BASE_URLCHAT_RELAY_TENANT_ID=019e4ae7-1a2b-7c3d-8e4f-5a6b7c8d9e0fCHAT_RELAY_TENANT_SECRET=sk_... # SECRET — never commit
# Widget / in-app SDK (public .env — the widget key is not secret)CHAT_TENANT_ID=019e4ae7-1a2b-7c3d-8e4f-5a6b7c8d9e0fCHAT_WIDGET_PUBLIC_KEY=pk_...The widget_public_key is not a secret: it pairs with the tenant_id to
route widget traffic and verify allowed_origins. The tenant_secret,
however, signs your backend calls — keep it server-side.
Step 3 — Drop in the widget
Section titled “Step 3 — Drop in the widget”With @bloonio/chat-angular, declare the provider then drop the launcher
anywhere. Full details on Widget & SDK.
import { provideBloonioChat } from '@bloonio/chat-angular';
export const appConfig = { providers: [ provideBloonioChat({ tenantId: '019e4ae7-1a2b-7c3d-8e4f-5a6b7c8d9e0f', publicKey: 'pk_...', baseUrl: '$BASE_URL', locale: 'en', }), ],};// a standalone componentimport { BloonioChatLauncherComponent } from '@bloonio/chat-angular';
@Component({ standalone: true, imports: [BloonioChatLauncherComponent], template: `<router-outlet /> <bloonio-chat-launcher />`,})export class AppComponent {}Your page’s origin must be listed in allowed_origins, otherwise the relay
refuses to create the visitor session (403).
Step 4 — Sign a backend call
Section titled “Step 4 — Sign a backend call”Backend → relay calls (/api/v1/relay/*) are signed with HMAC#1. The
Python SDK signs for you; here is the example of minting an operator token,
where your backend delegates its identity to the relay.
from bloonio_chat_relay_client import get_chat_client
chat = get_chat_client() # reads BLOONIO_CHAT_* from the environmentconvo = chat.create_conversation( visitor_user_id="user-123", visitor_display_name="Mary", locale="en",)chat.send_message(convo.id, role="visitor", content="Where is my order?")# X-Bloonio-Signature = hex(hmac_sha256(tenant_secret, f"{ts_ms}.{sha256_hex(body)}"))curl $BASE_URL/api/v1/relay/fetch/operator-token \ -X POST \ -H "X-Bloonio-Tenant-Id: 019e4ae7-1a2b-7c3d-8e4f-5a6b7c8d9e0f" \ -H "X-Bloonio-Timestamp: 1718960000000" \ -H "X-Bloonio-Signature: <signature>" \ -H "Content-Type: application/json" \ -d '{"email": "merchant@acme.com"}'What just happened
Section titled “What just happened”- You provisioned a tenant with the admin key and captured its three credentials (shown only once).
- The widget authenticates with the relay using the
widget_public_key+ thetenant_id, and creates a visitor session if the origin is allowed. - Your backend signs its calls with HMAC#1 using the
tenant_secret; the relay verifies the signature, the time window and the tenant status before routing tobloonio_chat_api.
Next steps
Section titled “Next steps”- Wire up human operators. See Operators.
- Receive events on your backend. See Webhooks.
- Rotate or suspend a tenant. See Tenant management.
- Integrate in self-service, without an admin key. See Console.