Supafone Labs ยท Documentation

๐Ÿ—๏ธ Hosted Agent Builder#

The hosted agent builder creates complete Supafone agents with managed voices, stages, tools, artifacts, widget sync, and Supafone Pro watcher attached.

There are two builder modes:

The builder UI should start with the one sl_ Labs key and the hosted Agent Factory path. BYOK provider credentials should live behind an advanced drawer. After a working agent is created, the builder should export the exact same configuration as TypeScript, Python, REST, MCP, and JSON.

The builder should preserve the product hierarchy:

RoleBuilder meaning
Primary: model supervisorVoice Watcher supervises and improves the live agent; voiceWatcher is on by default.
Secondary: Agent FactoryCreate a complete hosted agent with managed defaults and no required vendor keys.

When users open BYOK, split hosted-delivery settings into three drawers:

BYOK drawerExamples
Agent/provider stackFourteen audited runtime adapters
TelephonyTwilio, Telnyx, Plivo, SignalWire, SIP/custom trunks
TTSCartesia, ElevenLabs, Inworld, Deepgram, custom TTS

Recording and transcription should be explicit controls: audio recording, transcription, PII redaction, retention days, and consent announcement.

Programmatic Hosted Agent Builder#

ts
import { Supafone } from "supafone-labs";

const supafone = new Supafone({
  apiKey: process.env.SUPAFONE_TOKEN!,
  voiceWatcher: true, // default on โ€” provisions agents under the Voice Watcher framework
});

const inbound = await supafone.labs.agents.createInbound({
  agentKey: "northline-intake",
  name: "Northline intake",
  assistantName: "Maya",
  businessName: "Northline",
  description: "Answer new inquiries, capture the facts that matter, and book or route the next step.",
  websiteUrl: "https://northline.example",
  presetKey: "general_intake_receptionist",
  runtimeMode: "multi_stage",
  labs: { enabled: true, model: "gemma" },
  tools: {
    callRouting: true,
    scheduling: true,
    sms: true,
    email: true,
    firmKnowledge: true,
    voicemail: true
  }
});

console.log(inbound.call_plan?.call_stages); // reviewed JSON now running

Review before creation#

Products that need an approval step can preview first, show the plan in their own UI, let an operator edit it, and create from the approved JSON:

ts
const plan = await supafone.generateCallStages({
  direction: "inbound",
  businessName: "Northline",
  description: "Answer new inquiries, capture the facts that matter, and book or route the next step.",
  stageCount: 5,
  stageDetail: "detailed",
});

await supafone.labs.agents.createInbound({
  agentKey: "northline-intake",
  name: "Northline intake",
  callStages: plan.call_stages,
});

The equivalent REST endpoint is POST /api/v1/labs/agent-plans; Python uses generate_call_stages(); MCP uses generate_call_stages. All four interfaces share one plan contract and one Supafone credential.

To add a number, use createInboundWithNumber() or createOutboundWithNumber(). Choose the shared pool unless the user explicitly selects a paid reserved number.

ts
const withNumber = await supafone.labs.agents.createInboundWithNumber({
  agentKey: "northline-phone",
  name: "Northline phone intake",
  number: {
    search: { areaCode: "415" },
    numberStrategy: "default_pool"
  },
  labs: { enabled: true, model: "gemma" }
});

Discovery Before Creation#

ts
const capabilities = await supafone.labs.capabilities();
const presets = await supafone.labs.presets.list();
const tools = await supafone.labs.tools.list();
const voices = await supafone.labs.voices.list({ provider: "cartesia" });

Use discovery to render UI options rather than hard-coding provider inventory.

Labs Cloud Test Builder#

The Labs Cloud builder runs supervised test turns and saves configuration under the logged-in account. Call login() first.

ts
const supafone = new Supafone({
  apiKey: process.env.SUPAFONE_LABS_API_KEY!,
});

await supafone.login(process.env.SM_EMAIL!, process.env.SM_PASSWORD!);

await supafone.builder.saveConfig({
  agent_prompt: "You are a warm intake agent. Never quote fees.",
  agent_label: "intake",
  framework: "ultravox",
  llm: { provider: "hosted" }
});

const turn = await supafone.builder.chat("call-1", [
  { role: "agent", text: "Hi, how can I help?" },
  { role: "caller", text: "What do you charge? Give me a number." }
]);

console.log(turn.whisper);
console.log(turn.agent_reply);

Finish a test call to grade it and feed the optimizer:

ts
await supafone.builder.finish("call-1", [
  { role: "agent", text: "Hi, how can I help?" },
  { role: "caller", text: "What do you charge?" },
  { role: "whisper", text: "Do not quote fees; offer to connect them." },
  { role: "agent", text: "I cannot quote fees, but I can connect you with the team." }
]);

Builder Copilot Wizard#

POST /v1/builder/wizard on Labs Cloud powers the conversational copilot in the labs.supafone.ai builder: one copilot turn takes developer prose in and returns validated field updates out. The caller sends a fields catalog (key, label, type, options) plus the current draft; the response is {updates, reply} with every value clamped to the caller's catalog โ€” a deterministic contract the UI can apply directly to the real form. It authenticates with an sl_ key and bills one oracle call per turn (only when the model actually ran).

http
POST https://api.labs.supafone.ai/v1/builder/wizard
Authorization: Bearer sl_live_...

{
  "message": "Outbound roofing quotes, warm tone, 415 number",
  "draft": {"direction": ""},
  "fields": [
    {"key": "direction", "label": "Direction", "type": "choice", "options": ["inbound", "outbound"]},
    {"key": "agent_prompt", "label": "Prompt", "type": "text"}
  ]
}

Builder Contract#

The builder stores:

Blank secret fields in update payloads mean "keep the previously saved value".

View raw Markdown