Outbound Calls

View as Markdown

Use start_outbound_call() to dial any phone number and connect it to your agent. This is the production outbound surface - full variables support for per-call personalization, optional caller-ID rotation, and version pinning.

Not to be confused with /agent/{id}/versions/{versionId}/test-call. That endpoint is a debug surface bound to a specific agent draft or version. It only accepts mode and toPhone, doesn’t carry per-call variables, and counts against test-call slot limits. For real outbound traffic - campaigns, lead callbacks, anything customer-facing - use the pattern on this page (which maps to POST /conversation/outbound).

Basic Call

from smallestai import SmallestAI
# Reads SMALLEST_API_KEY from the environment, or pass api_key="sk_..." explicitly
client = SmallestAI()
response = client.atoms.calls.start_outbound_call(
agent_id="your-agent-id",
phone_number="+14155551234",
)
print(f"Call started: {response.data.conversation_id}")

Get your API key at app.smallest.ai/dashboard/api-keys and export it as SMALLEST_API_KEY, or pass SmallestAI(api_key="sk_...") directly.

Parameters

These are the parameters the Python SDK’s start_outbound_call() method accepts today.

ParameterTypeRequiredDescription
agent_idstringYesID of your agent (from the dashboard).
phone_numberstringYesE.164 format phone number (e.g. +14155551234, +919876543210).
variablesobjectNoPer-call values that override the agent’s defaultVariables for this conversation. Keys are variable names; values must be string, number, or boolean. Nested objects are not supported. See Personalization below.
from_numberstringNo (required after the migration window)E.164 caller ID to dial from. Matched exactly against numbers your organization owns (rented, or a caller ID on an outbound SIP trunk); no normalization is applied. If omitted, the call uses the deprecated caller-ID bridge (the agent’s attached caller IDs, first attached wins) and the response carries Deprecation: true; with none attached the call is refused with 400. There is no fallback to a platform number.
from_product_idstringNoLegacy. ID of the phone-number product to dial from. Resolved to its number before dialing. Prefer from_number for new integrations.

Campaigns take a different field: fromNumbers on POST /campaign (several caller IDs rotate across audience members, retries reuse the number the failed attempt used, and the list freezes at creation). It is not a /conversation/outbound parameter. See the Telephony API migration guide.

REST-only parameters

The underlying POST /conversation/outbound endpoint accepts one additional parameter that is not yet exposed by the Python SDK. To use it today, call the REST API directly with requests or httpx:

ParameterTypeDescription
versionIdstringPin the call to a specific published agent version. The call log is attributed to that version so you can A/B-test versions in production.
import os, requests
response = requests.post(
"https://api.smallest.ai/atoms/v1/conversation/outbound",
headers={"Authorization": f"Bearer {os.environ['SMALLEST_API_KEY']}"},
json={
"agentId": "your-agent-id",
"phoneNumber": "+14155551234",
"variables": {"customer_name": "Sarah Johnson", "package": "Gold"},
"versionId": "your-version-id",
},
)
response.raise_for_status()
print("Call started:", response.json()["data"]["conversationId"])

Personalization (passing per-call variables)

Pass variables to carry caller-specific values into the conversation - names, lead source, amounts, anything the agent should reference.

response = client.atoms.calls.start_outbound_call(
agent_id="your-agent-id",
phone_number="+14155551234",
variables={
"customer_name": "Sarah Johnson",
"package": "Gold",
"lead_source": "facebook_ad",
"vip": True,
},
)
  • Scalar values only. string, number, boolean. Nested objects are rejected with HTTP 400 ("Invalid input") - flatten the payload client-side (address_city instead of address: { city: ... }).
  • Variables are persisted with the call. They appear on the conversation log at data.variables and can be retrieved via GET /conversation/{id}.

See Variables for the agent-side guide to defining and referencing variables.

Response

# response.data.conversation_id = "CALL-1767900635803-8a3bee"
FieldTypeDescription
conversation_idstringUnique ID to track this call

Save this ID to retrieve transcripts and analytics later.

Error Handling

try:
response = client.atoms.calls.start_outbound_call(
agent_id="agent-123",
phone_number="+14155551234",
)
print(f"Call started: {response.data.conversation_id}")
except Exception as e:
error = str(e)
if "Invalid agent id" in error:
print("Error: Agent not found. Check your agent ID.")
elif "Invalid phone" in error:
print("Error: Invalid phone number. Use E.164 format.")
elif "401" in error:
print("Error: Check your API key.")
else:
print(f"Error: {error}")

Tips

Use a library like phonenumbers to validate before calling. Invalid numbers waste API calls.

Wait 5-10 seconds between calls to avoid rate limits.

Save them in your database to retrieve transcripts later.

Wrap calls in try/except and log failures for retry.