Skip to content

Channels & Access

Copy page

Channels & Access is the last group of Release settings: it decides how people and machines reach a Release, and what they’re allowed to spend once they do. Everything else on a Release — model, knowledge, safety, messaging — describes the assistant. This group describes its doors.

Seven settings sit in this group, in the order the dashboard presents them:

SettingRelease fieldAnswers
Text-to-speech / speech-to-textttsToolOverride, ttsVoiceOverride, sttToolOverrideWhich voice speaks, which transcriber listens
Testing domainstestingDomainsWhich origins chat without burning quota
MCP servermcpConfigWhich AI agents get programmatic access
SkillsskillConfigWhich tools the model may call mid-conversation
Anonymous chatallowAnonymousChatWhether strangers can chat without logging in
Free-chat gatefreeChatGateWhat they must prove before they do
Pricing tierspricingTiersWhat paying members may spend

Text-to-speech picks the voice your assistant speaks in; speech-to-text picks the engine that transcribes the user. Both are per-Release overrides — unset, they inherit the workspace default.

await divinci.releases.updateInWorkspace(workspaceId, "rel_abc123", {
ttsToolOverride: "cloudflare-aura-2",
ttsVoiceOverride: "aura-2-draco-en",
sttToolOverride: "deepgram-nova-3",
});

Provider keys. Cloudflare-hosted options are served on the platform’s own key — pick one and it works. Third-party providers that bill you directly (OpenAI Whisper, Deepgram Nova-3, ElevenLabs, Cartesia) require your own API key, registered on the workspace first; the key form adapts to whatever fields that specific provider needs. A Release pointed at a provider you haven’t keyed will not produce audio. See Provider Keys (BYOK).

TTS tool ids: browser-local, cloudflare-aura-1, cloudflare-aura-2, cloudflare-melotts, vertex-ai-standard, vertex-ai-neural2, vertex-ai-chirp3, vertex-ai-studio, cartesia-sonic, elevenlabs-tts, openai-tts, deepgram-tts.

STT tool ids: @cf/openai/whisper-large-v3-turbo (platform key), @openai/whisper-1 and deepgram-nova-3 (your key).

For phone calls specifically, the TTS provider you can reach is constrained by the Twilio transport — see Voice, Phone & SMS.

A testing domain is an origin whose messages don’t count against your usage quota. That’s the whole feature: it exists so a staging site or a localhost build can be exercised freely without consuming the allowance meant for real visitors.

It is unrelated to the voice settings above it in the form, and unrelated to CORS — it is a quota exemption, not an access grant.

await divinci.releases.updateInWorkspace(workspaceId, "rel_abc123", {
testingDomains: [
"staging.example.com", // exact host
"*.dev.example.com", // wildcard — one label
"localhost", // local development
"127.0.0.1",
],
});

Three pattern forms are accepted: an exact host, a wildcard (*. plus a domain, matching one leading label), and the literals localhost / 127.0.0.1. The list replaces the stored one — send the full set, and set it before publishing, since a published Release is locked for draft edits.

Publishing a Release as an MCP server hands another AI agent programmatic access to it — the same tools your chat assistant has, exposed over the Model Context Protocol. Configure it on mcpConfig; the full field table, endpoint URL and authentication modes live on Release as an MCP Server and Releases → MCP server config.

Two settings in this section are worth calling out here, because both are easy to get backwards.

maxSpendPerTokenCents caps how much a single MCP token can spend before it stops working (default 1000 = $10.00). It is your blast-radius limit if a credential leaks — set it to the smallest number a legitimate consumer needs.

skillConfig is the master switch for tool calling: with it enabled, a qualifying turn runs a loop — call model, execute tool, feed the result back — letting the assistant search, fetch, or take actions mid-conversation instead of answering from the prompt alone.

await divinci.releases.updateInWorkspace(workspaceId, "rel_abc123", {
skillConfig: {
enabled: true,
maxToolIterations: 5,
catalogSkills: { "6a67afca5599956295482dfc": ["sendEmail"] },
mcpSkills: { "6a72d8ae5c76b78e24589e85": [] }, // [] = all of that server's tools
toolCallingAssistant: { id: "@cf/moonshotai/kimi-k2.7-code" },
},
});
FieldMeaning
enabledMaster switch. While false the loop never runs, whatever skills are attached.
catalogSkillsMap of skill instance id → the action names it may run. [] = all of that skill’s actions.
mcpSkillsMap of connected MCP-server id → the tool ids exposed. [] = all of that server’s active tools.
toolCallingAssistantThe model that runs the tool loop.
fallbackToolCallingAssistantsOrdered retry chain when the tool model returns a retryable failure.
maxToolIterationsHard ceiling on tool-call rounds in a single turn.

Tools come from two places. Skills are Divinci’s built-in third-party integrations — some, like web search, connect in one click with no OAuth. MCP skills are external MCP servers you connect with OAuth or a static API key. Once either is connected, each of its actions or tools becomes individually selectable here.

The tool-calling assistant can differ from the answering model. Point it at a separate model and tool results are handed back to your primary assistant, which composes the final reply — so a cheap tool-capable model can drive the loop while your preferred model does the writing. When you enable the loop without naming one, it defaults to the Release’s own primary assistant, which must then itself support native tool calling or the save is rejected.

Lets people talk to the Release without logging in, with a hard cap on message count per conversation. Three fields control it — allowAnonymousChat, maxAnonymousChatMessages, requireSignedAnonymousChat — documented in full at Releases → Anonymous chat.

It is also the prerequisite for the next section: the free-chat gate has nothing to gate until anonymous chat is on, which is why the dashboard only reveals it once you enable this.

The verification layer in front of anonymous chat: a Turnstile CAPTCHA, and optionally email verification, plus per-email and per-device quotas — all enforced before any message reaches the model.

Four modes: none, captcha-only, captcha+otp, captcha+magic-link. captcha-only uses Divinci’s platform-managed Turnstile widget with no setup at all; bring your own Cloudflare widget by supplying a sitekey and a secret reference instead. Higher modes add OTP or magic-link email verification on top.

Modes, quota knobs, and the platform-vs-BYO Turnstile split are documented at Security & Abuse Protection → Free-chat gate.

Pricing tiers define paid, spend-based membership levels for this specific Release. Each tier grants its members a spend allowance per time window; an end user pays via Stripe to move up a tier. The Release owner’s wallet still funds inference — a tier unlocks how much a member may consume, it does not change who pays the provider.

Each tier carries a slug, a display name, an order, an optional priceCents (omitted or 0 = a free tier, not purchasable), and one or more spend windows. A window is a duration plus a spend ceiling — hourly, daily, weekly, monthly, or unlimited. Exactly one tier should set isDefault: true; that’s where a logged-in-but-unpaid user lands.

await divinci.releases.updateInWorkspace(workspaceId, "rel_abc123", {
pricingTiers: [
{
slug: "free",
name: "Free",
order: 0,
isDefault: true,
// 1 day, $1.00 — limits are nano-USD decimal STRINGS, not numbers
windowValidations: [{ durationMs: 86_400_000, limitNanoUSD: "1000000000" }],
},
{
slug: "pro",
name: "Pro",
order: 1,
priceCents: 2900,
currency: "usd",
windowValidations: [{ durationMs: 86_400_000, limitNanoUSD: "25000000000" }],
},
],
});

That’s the last group. Once saved, the Release is fully configured, and from here you can:

  • Keep editing — every change bumps the version.
  • Fork it into a fresh draft — leaves the live Release serving traffic while you work.
  • Deprecate it when it’s time to retire.

See Releases → Lifecycle for the publish, fork and deprecate endpoints — and for why the SDK’s activate() / archive() are not the way to do any of it.