# connect11 — complete integration guide for AI agents connect11 (by 1-TO-ALL) is a real-time platform: voice, video, and AI agents in one SDK and one REST API, running on the 1-TO-ALL network, built in Thailand. This guide contains everything an AI agent needs to integrate connect11 into an application correctly on the first attempt. All signatures and endpoints below are exact. Base URL: https://api.connect11.ai/api/v1 Console (human sign-in, API keys, top-up): https://connect11.ai/console Human docs: https://connect11.ai/docs Support: 1650 · contact@1toall.co.th ## The mental model 1. Your customer's server holds a connect11 API key (`c11_live_…`). 2. For every participant who wants to join a call, the server mints a short-lived room token — via `POST /realtime/tokens` (recommended) or the `@connect11/server` package. 3. The browser/app calls `connect11.join(room, { token, url })` from `@connect11/client`. 4. AI agents (live translator, voice bot, chat bot) are requested at token mint or attached with `room.addAgent()`. 5. Billing is prepaid: a THB wallet is debited per participant-minute and per agent-minute. When the wallet is empty, token minting returns 402. ## Hard rules (violating these is the #1 cause of broken integrations) - NEVER put the API key in browser/client code, environment files shipped to clients, or URLs. It belongs on a server only. - NEVER cache or reuse room tokens. Mint one per participant per join. TTL is clamped to 60–900 seconds. - Room and identity names must match `[A-Za-z0-9_-]`, 1–96 chars. No spaces, no dots, no colons. - Do NOT add your own tenant prefixes to room names — the platform namespaces rooms and identities server-side. In usage records you'll see them prefixed (`org_--room`, `::identity`); that's normal. - Use the `url` returned by the token endpoint. Don't hardcode a realtime URL. - Handle 402 (wallet empty) and 429 (rate limit: 60 token mints/minute/key) explicitly. Back off on 429; surface a "top up" message on 402. - `room.dial()` throws `pstn_not_enabled` unless telephony has been enabled for the account. Don't retry it in a loop; tell the user to contact 1-TO-ALL (1650). ## Install ``` npm install @connect11/client # browser / app npm install @connect11/server # Node server (token minting) — optional if you use the REST endpoint ``` ## Server side — minting tokens ### Option A (recommended): REST ``` POST https://api.connect11.ai/api/v1/realtime/tokens Authorization: Bearer c11_live_xxxxxxxx_ Content-Type: application/json { "room": "sales-7", "identity": "user-42", "name": "Nok", // optional display name "ttl_seconds": 600, // optional, clamped 60–900 "agents": [ // optional; dispatches an AI agent into the room { "type": "translator", "from": "th", "to": "en" } ] } ``` In-person two-way translation (two people sharing ONE device, hands-free, no turn-taking) — pass the language PAIR instead of from/to; the agent auto-detects which of the two languages is being spoken and speaks the other: ``` { "room": "counter-1", "identity": "shared-phone", "agents": [ { "type": "translator", "pair": ["th", "en"] } ] } ``` Rules for `pair`: exactly two distinct BCP-47-ish codes (`^[a-z]{2,8}(-[A-Za-z0-9]{2,8})?$`), only valid with `"type": "translator"`. Never send a `mode` of "conversation" in any attribute or metadata — the pair alone selects two-way; a "conversation" mode selects a different multi-device pipeline and the one-device session will produce nothing. Response 200: ``` { "token": "", "url": "wss://…", "expires_at": 1782561600, "agent_dispatch": "created" } ``` Pass `token` and `url` to the client verbatim. `agent_dispatch` appears only when `agents` was requested: `created` | `existed` (someone in the room already dispatched it) | `failed:` (token still valid — mint again to retry the dispatch). Errors: 400 `invalid_room` / `invalid_identity` / `invalid_agent_type` / `invalid_lang` / `invalid_pair` / `pair_requires_translator` · 401 invalid or expired key · 402 `insufficient_balance` / `no_billable_wallet` · 403 missing `realtime:token` scope · 429 `rate_limited` · 503 `realtime_not_configured`. ### Option B: @connect11/server (Node) ```ts import { mintToken } from "@connect11/server"; // Reads CONNECT11_API_KEY / CONNECT11_API_SECRET from env unless passed in opts. const token = await mintToken({ room: "sales-7", identity: "user-42", name: "Nok", // optional ttlSeconds: 600, // optional, clamped 60–900 canPublish: true, // optional grants, default true canSubscribe: true, canPublishData: true, }); ``` Fine-grained form: ```ts import { AccessToken } from "@connect11/server"; const at = new AccessToken(apiKey, apiSecret, { identity: "user-42", ttlSeconds: 600 }); const token = await at.grantRoom("sales-7", { canPublish: true }).toJwt(); ``` ## Client side — @connect11/client (exact public surface) ```ts import { connect11, Connect11Error } from "@connect11/client"; import type { Room, Participant, AgentOptions, JoinOptions } from "@connect11/client"; connect11.configure({ url: "wss://…" }); // optional: set once, join() can then omit url const room: Room = await connect11.join("sales-7", { token, // required — server-minted url, // required unless configure() was called autoSubscribe: true, // default true }); // Media await room.publishMic(); await room.publishCamera(); await room.unpublishMic(); // Events (chainable) room .on("participant", (p: Participant) => { // p.identity: string; p.name?: string; p.isAgent: boolean p.audio.subscribe(); // only needed when autoSubscribe: false p.video.subscribe(); }) .on("message", ({ from, text }) => { /* data-channel message */ }) .on("disconnected", () => { /* session ended */ }); // AI agents — translator | voicebot | chatbot await room.addAgent({ type: "translator", from: "th", to: "en" }); await room.addAgent({ type: "voicebot" }); await room.addAgent({ type: "chatbot" }); // Telephony (per-project): throws Connect11Error("pstn_not_enabled") until enabled // room.dial("+66…"); // Leave await room.disconnect(); ``` Error handling: ```ts try { await connect11.join(roomName, { token }); } catch (e) { if (e instanceof Connect11Error) { // e.code: "no_url" | "pstn_not_enabled" | "not_connected" } } ``` - `no_url` — you passed no `url` and never called `configure()`. Use the `url` from the token response. - `not_connected` — a Room method was called after `disconnect()`. - `pstn_not_enabled` — telephony not enabled for this account. ## Usage & billing (read APIs) ``` GET /realtime/usage/summary Authorization: Bearer c11_… → { customer_id, sessions, minutes, amount, currency: "THB" } GET /realtime/usage/records Authorization: Bearer c11_… → per-session records: room, identity, kind ("participant"|"agent"), seconds, minutes, amount, ledger_entry_id ``` Rates are per-account and shown in the console. Wallet, ledger, API-key management, and top-up (online checkout or bank transfer) are in the console: https://connect11.ai/console. Creating API keys requires one-time verification (KYC) and returns the key exactly once. Rotation issues a new key with a 24-hour grace period on the old one. ## Pre-flight checklist (verify before declaring the integration done) 1. API key lives only server-side; grep client bundle for `c11_` to confirm. 2. Token minted per join with the participant's real identity (not a shared identity). 3. `url` from the token response is passed to `join()` (or `configure()` was called with it). 4. Room/identity names match `[A-Za-z0-9_-]{1,96}`. 5. 402 → user-facing "top up" path; 429 → exponential backoff; both tested. 6. `disconnected` event handled (UI returns to a sane state). 7. If agents are used: requested via `agents` at mint (preferred) or `addAgent()` after join; translator has `from`/`to`. 8. No vendor or engine names surfaced in your UI — the platform is connect11, by 1-TO-ALL. 9. Mic/camera released on leave (`room.disconnect()` on unmount/navigation). 10. Tested with a `c11_test_` key before switching to `c11_live_`. ## What connect11 is NOT (avoid inventing these) - There is no client-side token minting. No `connect11.createToken()` exists. - There is no `room.record()` / recording API in the public SDK today. - There are no per-room webhooks for customers today; usage is pulled via the usage endpoints. - Agent types are exactly: translator, voicebot, chatbot. Nothing else is accepted. - SMS, click-to-call embeds, and phone-number provisioning are operator products sold by 1-TO-ALL — contact 1650; they are not in this SDK's public surface yet.