# 🚀 Quickstart

This page shows both Supafone Labs paths: hosted complete agents and
bring-your-stack supervision.

## 1. Install

```bash
pip install "supafone-labs[all]"
npm i supafone-labs
```

## 2. Get a Key

One `sl_` Labs key is all you need — since 0.4.4 it authenticates on **both**
APIs ([one-key auth](api-keys-and-auth.md)): Labs Cloud
(`api.labs.supafone.ai`) natively, and the product API (`api.supafone.ai`) via
key introspection, as long as an app.supafone.ai account exists with the same
email.

```bash
curl -X POST https://api.labs.supafone.ai/v1/signup \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com"}'

export SUPAFONE_TOKEN=sl_live_...   # one env var: MCP + both SDKs
```

That one `sl_` key is the default for everything below. For hosted-agent-only
setups you can optionally still mint a scoped `sf_live_...` key from the Supafone
account-admin flow and point it at `https://api.supafone.ai` — but the `sl_` key
already covers that surface, so it is the exception, not the default.

## 3. Supervise an Existing Familiar Framework

Start with the voice framework or provider you already know. Supafone observes
its native events and returns a provider-specific action only when the runtime
contract supports one:

```python
import supafone_labs

brain = supafone_labs.supercharge(
    my_agent,
    scenario="legal_intake",
)

result = await brain.observe(raw_platform_event)

if result.actions:
    await my_agent.deliver(result.actions[0])
```

With `SUPAFONE_LABS_API_KEY=sl_live_...`, the supervisor, TTS, and STT can use
Labs Cloud. Without it, the SDK can run with your own vendor keys or offline
fake providers for tests. See [Framework Coverage](framework-support.md) before
assuming an adapter has a live control channel: adapter support and
Supafone-hosted runtime support are different claims.

## 4. Create a Managed Agent Factory Agent

TypeScript:

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

const supafone = new Supafone({
  apiKey: process.env.SUPAFONE_TOKEN!, // sl_ key — cross-fills both surfaces
  voiceWatcher: true, // default on — provisions agents under the Voice Watcher framework; set false for a raw agent
});

const agent = await supafone.labs.agents.createInboundWithNumber({
  agentKey: "northline-intake",
  name: "Northline intake",
  assistantName: "Maya",
  businessName: "Northline",
  description: "Answer new inquiries, understand the request, and book the right next step.",
  websiteUrl: "https://northline.example",
  number: {
    search: { areaCode: "415" },
    numberStrategy: "default_pool"
  },
  voice: { provider: "cartesia", voiceId: "Jacqueline" },
  labs: { enabled: true, model: "gemma" },
  tools: {
    callRouting: true,
    scheduling: true,
    sms: true,
    email: true,
    firmKnowledge: true,
    voicemail: true
  }
});

console.log(agent.agent.agent_key);
console.log(agent.number?.number.phone_number);
console.log(agent.widget?.snippet);
console.log(agent.call_plan?.call_stages); // the reviewed JSON now running on the agent
```

The default pool is the safe starting point. Use `numberStrategy: "dedicated"`
or `numberStrategy: "premium"` only after the customer explicitly chooses a paid
reserved number.

Python:

```python
from supafone_labs import Supafone

supafone = Supafone(api_key="sl_live_...", voice_watcher=True)  # one key; watcher on by default

agent = supafone.labs.agents.create_inbound_with_number({
    "agentKey": "northline-intake",
    "name": "Northline intake",
    "assistantName": "Maya",
    "businessName": "Northline",
    "description": "Answer new inquiries, understand the request, and book the right next step.",
    "websiteUrl": "https://northline.example",
    "number": {
        "search": {"areaCode": "415"},
        "numberStrategy": "default_pool",
    },
    "voice": {"provider": "cartesia", "voiceId": "Jacqueline"},
    "labs": {"enabled": True, "model": "gemma"},
    "tools": {
        "callRouting": True,
        "scheduling": True,
        "sms": True,
        "email": True,
        "firmKnowledge": True,
        "voicemail": True,
    },
})

print(agent["agent"]["agent_key"])
print(agent.get("number", {}).get("number", {}).get("phone_number"))
print(agent["call_plan"]["call_stages"])
```

That one description is enough for the default hosted planner to write the
agent-wide prompt and a validated five-stage flow. You can preview it first
with `supafone.generateCallStages(...)` / `supafone.generate_call_stages(...)`,
edit the returned JSON, or pass an explicit stage array for a reviewed flow.
Supafone's model credential stays on the server.

## 5. Check Balance and Logs

```bash
curl https://api.labs.supafone.ai/v1/billing/balance \
  -H "Authorization: Bearer $SUPAFONE_TOKEN"

curl https://api.labs.supafone.ai/v1/logs?limit=20 \
  -H "Authorization: Bearer $SUPAFONE_TOKEN"
```

## 6. Smoke Test Hosted Agents

```bash
cd supafone-labs
SUPAFONE_API_KEY=sl_live_... \
SUPAFONE_API_BASE_URL=https://api.supafone.ai \
npx tsx examples/smoke-hosted-agent.ts
```

The smoke test checks capabilities, presets, voices, agent creation, fetch by
key, Supafone-managed providers, no required developer provider keys, and a web
widget snippet.

Next: [SDK Parity](sdk-parity.md), [Agent Factory](agent-factory.md),
[Voices and Previews](voices-and-previews.md), and [Log Streaming](log-streaming.md).
