Hosted Mode

Hosted mode is the easiest way to ship something useful.

You provide the prompt. Saperly handles the call loop.

Hosted mode costs 0.26/min,billedpersecondforZoneA(US/Canada).A3minutecall=0.26/min, billed per second for Zone A (US/Canada). A 3-minute call = 0.78. The line itself costs $2.50 per 30-day period (first number free for 30 days). International destinations use Zone B (×2) and Zone C (×3) — see Voice zones.
Compliance is opt-in. Saperly does NOT verify consent or play AI disclosures unless you set compliance_enabled: true on the line. With the flag off, TCPA, GDPR, and local telecom compliance are the customer’s responsibility. See Compliance and Consent for the full liability framing and how to opt in.

When to use it

Use hosted mode if:

  • you want to launch quickly
  • your call logic is mostly prompt-driven
  • you do not want to run a webhook server yet
  • you want a receptionist, intake agent, reminder bot, or FAQ line

Create a hosted line

$curl -X POST https://saperly.com/api/v1/lines \
> -H "Authorization: Bearer sk_live_..." \
> -H "Content-Type: application/json" \
> -d '{
> "name": "Receptionist",
> "mode": "hosted",
> "system_prompt": "You are a friendly receptionist for Acme Corp. Answer questions about hours, location, pricing, and appointment availability. Keep answers concise.",
> "begin_message": "Thanks for calling Acme Corp. How can I help?",
> "voice": "21m00Tcm4TlvDq8ikWAM",
> "context_limit": 20
> }'
The TypeScript SDK type for mode does not yet include hosted. Cast to another allowed value as shown, or call the API directly with curl or Python until the SDK ships the updated type.

Important fields

system_prompt

This is the core behavior contract for the line.

Be specific. Tell the agent:

  • who it is
  • what it can help with
  • what it must never do
  • when it should escalate or stop

begin_message

Use this to avoid dead air at the start of the call.

If you leave it out, the line waits for the caller to speak first.

voice

Use GET /api/v1/voices to list available voice IDs before you pick one.

context_limit

Higher values preserve more conversation history but use more tokens and may slow longer calls.

Prompt engineering examples

The quality of your system_prompt (or topic for one-off calls) decides how the line behaves. Two concrete patterns to start from:

Receptionist

1{
2 "system_prompt": "You are the front desk at Acme Dental. Office hours are Mon-Fri 8am-5pm. You can schedule, reschedule, or cancel appointments. If the caller has a dental emergency, tell them to call 911 or go to the nearest ER. Never provide medical advice."
3}

Appointment reminder (one-off conversation call)

1{
2 "topic": "Call the patient to confirm their cleaning appointment tomorrow at 2pm. If they want to reschedule, offer the next three available slots: Wednesday 10am, Thursday 3pm, Friday 9am."
3}
Scope the prompt tightly. A short, specific prompt outperforms a long, open-ended one.

One-off conversation calls

If the prompt changes per call, use the conversation call endpoint instead of creating a new line every time.

$curl -X POST https://saperly.com/api/v1/calls/conversation \
> -H "Authorization: Bearer sk_live_..." \
> -H "Content-Type: application/json" \
> -d '{
> "line_id": "LINE_ID",
> "to_number": "+14155551234",
> "topic": "Call the customer to confirm their appointment tomorrow at 2pm and offer rescheduling if needed.",
> "begin_message": "Hi, this is Acme calling to confirm your appointment tomorrow at 2pm."
> }'

Good first hosted-mode use cases

  • front desk and receptionist
  • FAQ line
  • appointment reminders
  • after-hours triage
  • simple order status assistant

When not to use hosted mode

Do not start here if your call needs:

  • deep internal business logic
  • privileged backend actions
  • strict deterministic flow control
  • your own model runtime

In those cases, use Webhook Mode or Audio Mode.

Testing your hosted line

Once the line is created, walk through the full loop end to end before you put it in front of real callers.

1

Call your number

Dial the provisioned number returned by the create call. Any mobile phone works.

2

Verify the greeting

You should hear begin_message spoken aloud in the voice you selected. If there is silence, the line is likely waiting for you to speak first because begin_message was not set.

3

Have a short conversation

Ask 2-3 questions your system_prompt covers. Listen for on-topic answers and for the refusal behavior you defined (for example, the emergency handoff in the dental example).

4

Check the transcript

After you hang up, fetch the call to confirm Saperly captured it:

$curl https://saperly.com/api/v1/calls/CALL_ID \
> -H "Authorization: Bearer sk_live_..."

The response includes the full transcript.

5

Check billing

Confirm the charge landed on your account:

$curl https://saperly.com/api/v1/billing/balance \
> -H "Authorization: Bearer sk_live_..."

A 1-minute test call should reduce your balance by 26 cents.

If the AI does not respond after connecting, check: (1) your system_prompt is not empty, (2) the voice ID is valid (list with GET /api/v1/voices), (3) your balance is sufficient.

Call recording

Enable recording per line:

$curl -X POST https://saperly.com/api/v1/lines \
> -H "Authorization: Bearer sk_live_..." \
> -H "Content-Type: application/json" \
> -d '{
> "name": "Recorded line",
> "mode": "hosted",
> "system_prompt": "You are a helpful assistant.",
> "recording_enabled": true
> }'

Retrieve the recording URL from the call object after the call ends:

$curl https://saperly.com/api/v1/calls/CALL_ID \
> -H "Authorization: Bearer sk_live_..."

The response includes recording_url and transcript fields when recording is enabled.

Inbound SMS

Hosted mode bundles ConvAI for voice. Voice mode does not gate SMS.

Every line — hosted, webhook, or audio — receives inbound SMS. Saperly records the consent record and logs a sms_received compliance event regardless of voice mode.

To auto-reply, set webhookUrl on the line. Your server receives the sms_received event and replies by calling POST /api/v1/messages with text generated by your own LLM:

$curl -X POST https://saperly.com/api/v1/lines \
> -H "Authorization: Bearer sk_live_..." \
> -H "Content-Type: application/json" \
> -d '{
> "name": "Receptionist",
> "mode": "hosted",
> "system_prompt": "...",
> "webhook_url": "https://your-app.example.com/saperly/sms"
> }'

A hosted line without webhookUrl still records consent and the compliance event on inbound SMS, but Saperly will not deliver the event to a customer endpoint and your code has nothing to reply with. See SMS and Conversations for the reply API and 24-hour conversation window.