saperly

Your first call

Provision a hosted line, call it, and read back the transcript — the voice version of the quickstart, in about five minutes.

Goal: stand up a phone number your agent answers, call it from your own phone, and read back what was said. This is the voice counterpart to the Quickstart — same five minutes, but you end up talking to your agent out loud.

You'll need a Saperly account and an API key. Create both from the dashboard onboarding (see the Quickstart).

Provision a hosted line

A hosted line is a real number answered by an in-network voice assistant — speech-to-text, the model, and text-to-speech all run in the network, so no call audio ever reaches your servers. The systemPrompt is your agent's instructions.

import { Saperly } from '@saperly/sdk'

const saperly = new Saperly({ apiKey: process.env.SAPERLY_API_KEY! })

const line = await saperly.lines.create({
  name: 'support agent',
  mode: 'hosted',
  systemPrompt:
    'You are a friendly support agent for Acme Inc. Greet the caller, answer ' +
    'their question, and keep replies short.',
  voice: 'aria',
})

console.log(line.phoneNumber) // → the number to call
import os
from saperly import SaperlyClient

saperly = SaperlyClient(api_key=os.environ["SAPERLY_API_KEY"])

line = saperly.lines.create(
    name="support agent",
    mode="hosted",
    system_prompt=(
        "You are a friendly support agent for Acme Inc. Greet the caller, "
        "answer their question, and keep replies short."
    ),
    voice="aria",
)

print(line.phone_number)  # → the number to call
curl -X POST https://api.saperly.com/api/v1/lines \
  -H "Authorization: Bearer $SAPERLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "support agent",
    "mode": "hosted",
    "system_prompt": "You are a friendly support agent for Acme Inc. Greet the caller, answer their question, and keep replies short.",
    "voice": "aria"
  }'

voice is a Saperly voice slug (for example aria or atlas). The call returns a real, certified number ready to ring.

Call it

Dial the phoneNumber from any phone. The hosted assistant picks up, speaks your greeting, and holds a real conversation driven by your systemPrompt. The compliance disclosure (when enabled) is spoken first, before anything else.

No webhook to wire

For an inbound call to a hosted line, there is nothing else to set up — the number answers itself. You only reach for webhooks when you want to be notified about calls, not to make them work.

See the call

After you hang up, the call shows up under your workspace with its outcome — who called, how long it ran, and how it ended.

# Most recent calls on your workspace
curl "https://api.saperly.com/api/v1/calls" \
  -H "Authorization: Bearer $SAPERLY_API_KEY"
const calls = await saperly.calls.list()
console.log(calls[0]) // status, direction, duration, from, to

Each call carries its status, direction, duration, and the numbers involved. The full turn-by-turn transcript — what the caller said and what your agent replied — is available on the v2 API at GET /calls/{id}/transcript (see the API reference). Audio stays in the network; you get the record.

What just happened

You provisioned a hosted line. One call gave you a certified number with an in-network voice agent attached — no media infrastructure of your own.

You talked to your agent. The hosted assistant ran the whole conversation in-network from your systemPrompt.

You got the record. The call's outcome is on your workspace, and the turn-by-turn transcript is a text fetch away — while the audio never left the network.

Next steps

  • Connections — hosted vs manual, and how a connection is reused across many numbers.
  • Manual mode — make your own model the brain on every call, relayed as text.
  • Voice channels — call your own coding agent (Claude Code / openclaw) and talk to it in its context.
  • Place & control calls — outbound calls, transfer, and live control.

On this page