Skip to main content

calle-ai

PyPI version Python versions CI License: MIT

Python server SDK for the CALL-E Developer API.

Use this SDK from backend services, workers, and other trusted server environments. Do not expose CALL-E API keys in browser code.

SDK 1.0 uses the single-target Calls API and the same result model as Goal Runs. A required closed scalar-object result schema defines the business fields. SDK wait helpers continue while result_status is pending, even after execution reaches completed. Empty {} is a ready result. Webhook data matches the persisted GET snapshot.

Documentation

SDK surface

  • client.calls creates, reads, and polls call tasks and lists call events.
  • client.goals lists and reads published Goals and runs them with structured results.
  • examples/webhook_server.py shows how to receive current terminal webhook events.

Install

Install the stable package from PyPI:

pip install calle-ai==1.0.1

For reproducible deployments, pin the package version selected by your dependency-management workflow.

Use a local checkout for development and package smoke tests:

bash scripts/validate.sh

Python 3.11 or newer is required.

Configuration

Create one CalleClient and close it when your process no longer needs it:

Option Required Description
api_key Yes CALL-E API key. Load it from a server-side secret store or environment variable.
base_url No API base URL. Defaults to https://api.heycall-e.com.
timeout No HTTP request timeout in seconds. Defaults to 30.0.
http_client No Configured httpx.Client used as-is. It must define the required base URL, authentication, transport, and timeout.

With the default HTTP client, use CalleClient as a context manager so the SDK closes its connection pool:

import os
from calle import CalleClient

with CalleClient(api_key=os.environ["CALLE_API_KEY"]) as client:
    call = client.calls.get("call_123")

API keys and diagnostic output

Use the complete API key issued by the CALL-E dashboard. <YOUR_CALLE_API_KEY> and the fallback keys in example scripts are non-working placeholders. Replace them with your own key; do not derive key validation or redaction patterns from a sample prefix.

Before logging or sharing diagnostics:

  • Prefer a small set of fields such as SDK version, HTTP status, and error code over dumping a full request, response, or error object.
  • Remove the entire Authorization header and configured secret values. Matching one key prefix is not sufficient.
  • Review phone fields and free text, including task, transcripts, summaries, evidence, custom results, metadata, and error details. The SDK preserves the returned task text, which may contain a phone number or other private data. Dashboard masking does not redact SDK output or raw API responses.

For example, a manually redacted response excerpt for sharing can omit all other fields and replace both the task and recipient phone:

{
  "status": "completed",
  "task": "[REDACTED]",
  "recipients": [{"phones": ["[REDACTED]"]}]
}

This is a diagnostic excerpt, not a create request. Inspect the final text before publishing it; these replacements are not a general-purpose PII filter.

Examples

Set the API key before running call examples:

export CALLE_API_KEY="<YOUR_CALLE_API_KEY>"
export CALLE_BASE_URL="https://api.heycall-e.com"
export CALLE_EXAMPLE_PHONE="+14155550100"

Run the create-and-wait example from a local checkout:

uv run python examples/create_and_wait.py

Run a published Goal with an explicit Goal, phone, variables, and durable idempotency key:

export CALLE_GOAL_ID="<PUBLISHED_GOAL_ID>"
export CALLE_GOAL_PHONE="<AUTHORIZED_E164_PHONE>"
export CALLE_GOAL_VARIABLES='{"name":"Alex"}'
export CALLE_IDEMPOTENCY_KEY="<DURABLE_WORKFLOW_KEY>"
uv run python examples/run_goal_and_wait.py

To use an approved non-production environment, explicitly set:

export CALLE_BASE_URL="<APPROVED_TEST_API_BASE_URL>"

Run the webhook receiver example:

uv run python examples/webhook_server.py

The webhook receiver listens on POST /calle/webhook and processes terminal event JSON. CALL-E sends terminal events only after the post-call outcome and requested structured results are finalized.

CALL-E webhook delivery does not use a webhook secret, CALL-E-Timestamp, or CALL-E-Signature. Use the required CALL-E-Event-Id header to deduplicate at-least-once deliveries before performing side effects. The receiver example parses JSON directly and checks that this header matches the body event id. It defaults to a 10 MiB request-body limit and returns 413 for larger payloads. Set CALLE_WEBHOOK_MAX_BODY_BYTES to match your ingress limits.

The bounded in-memory deduplication cache is only for local example use and retains the latest 10,000 event ids. Production deployments must use a production server or ingress with read deadlines and durable deduplication storage with an explicit retention policy.

The client.webhooks.verify and client.webhooks.unwrap methods implement the legacy signed-payload contract from SDK 0.2. They remain available for source compatibility but are deprecated and are not compatible with current unsigned CALL-E deliveries.

Quickstart

Run a reusable published Goal. The Goal owns its input and result schemas; each Run supplies only a phone number, per-Run variables, and a durable idempotency key:

import os
from calle import CalleClient

client = CalleClient(api_key=os.environ["CALLE_API_KEY"])

goal = client.goals.get("goal_delivery_confirmation")
print(goal["title"], goal["published_run_spec"]["input_schema"])

run = client.goals.run_and_wait(
    goal_id=goal["id"],
    phone="+14155550100",
    variables={
        "customer_name": "Taylor",
        "order_reference": "ORD-8472",
        "delivery_window": "July 24, 2:00-4:00 PM",
    },
    idempotency_key="delivery:ORD-8472:confirm-window:v1",
)

if run["result"] is not None:
    print(run["call_id"])
    print(run["result"])
else:
    print(run["error"])

Persist the idempotency key before the first request and reuse it for network retries. wait_for_result returns when result_status is no longer pending; an execution status of completed can still be waiting for result materialization.

Migration to SDK 1.0

The calls wrapper now submits one explicit phone to /v2/calls and requires an idempotency key. Keep the key for retries. The backend continues serving legacy integrations until their planned retirement at the end of 2026; keep SDK 0.7.x for historical legacy call IDs. Upgrade Goal Run integrations to 1.0 as well: old wait helpers can time out when both result and error are null.

call = client.calls.create_and_wait(
    task="Ask whether Friday lunch is confirmed.",
    phone="<AUTHORIZED_E164_PHONE>", region="US", locale="en-US",
    result_schema={
        "type": "object", "additionalProperties": False, "required": ["answer"],
        "properties": {"answer": {"type": "string", "enum": ["yes", "no", "unknown"]}},
    },
    idempotency_key="lunch:friday:confirmation:v1",
)
if call["error"] is None:
    print(call["result"])
else:
    print(call["error"])
# Cancel a queued call before provider submission:
# client.calls.cancel(call_id)

Replace recipient / recipients with phone and optional region and locale. Define the required result_schema (resultSchema in TypeScript) using Goal's calle.result.scalar-object.v1 profile: at most 32 scalar properties and additionalProperties: false. Flatten old nested fields; arrays and null values are unsupported. Old structured_result, result_error, summary, confidence and provider attempt fields are removed. Request business summaries or completion flags explicitly as scalar fields in the schema when needed. The Calls API does not support batch, scheduled or recurring calls.

Calls and Goal Runs always expose transcript, an array of recorded turns with speaker (bot, user, unknown), nullable offset_seconds, and text. Before execution ends or without available transcript, the array is empty. A pending, unavailable or failed business result does not remove an available terminal transcript. Webhook data uses the same shape.

The returned object is call. Consume result and error exactly as for Goal Runs. Poll while result_status is pending (resultStatus in TypeScript). No-answer, busy and declined are ordinary call_outcome values (callOutcome in TypeScript). Unavailable business evidence uses result_status=unavailable and error=null. Explicit schema-valid task fallbacks remain results. Technical failures use error. Cancellation uses result_status=not_applicable and no error. GET reads committed state and terminal webhooks contain the same ready snapshot. Deduplicate by event id.

Cancellation returns 409 call_cannot_cancel after provider submission begins. Calls accept immediate execution only. If authorization expires after submission, error.detail_code=authorization_expired means the provider may still complete the call; do not create an automatic replacement call.

Error handling

The SDK exports errors for API responses, authentication, rate limits, timeouts, and connection failures:

import os
from calle import CalleAPIError, CalleClient

with CalleClient(api_key=os.environ["CALLE_API_KEY"]) as client:
    try:
        client.calls.get("call_123")
    except CalleAPIError as error:
        print(error.status_code, error.code, error.details)
        raise

Release

This repository publishes the Python distribution calle-ai. Application code imports it as calle.

Merging to main runs CI and does not publish the package. A stable publish is triggered only by publishing a GitHub Release with a matching vX.Y.Z tag; manually running the workflow performs a dry run. See RELEASE.md for release gates and registry checks.

Support and security

Use GitHub Issues for reproducible SDK bugs and feature requests. Do not report vulnerabilities in a public issue. Follow SECURITY.md for private reporting.

License

This project is licensed under the MIT License. The same license applies to the published PyPI distributions calle-ai==0.6.0 and calle-ai==0.7.0.

Project Documents

Metadata

Release files for calle-ai 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for calle-ai 1.0.1
File Size Uploaded
calle_ai-1.0.1.tar.gz 159.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for calle-ai 1.0.1
File Interpreter ABI Platform
calle_ai-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 254.3 kB

Release files / calle_ai-1.0.1.tar.gz

Download URL calle_ai-1.0.1.tar.gz
Size 159.5 kB
Tags Source
SHA-256 checksum
How to use checksums
9f3237e6f0c582bd57b7daf5f0f11fcb78c0f576f1f38bc1d647a5674a1b2eb8
BLAKE2b-256 checksum
How to use checksums
91f9d7d1e0fdd70f7e4eb26c1c6b7897647410d528f4c2c9a22a484d2d778efa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / calle_ai-1.0.1-py3-none-any.whl

Download URL calle_ai-1.0.1-py3-none-any.whl
Size 94.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
206170838892a0b0197b581b4bbbb6bd04145594e91a38bb01acee2f0a3ab9aa
BLAKE2b-256 checksum
How to use checksums
a0a7061e79a83a9e431ed8285a1d8fef68cb882a10c09bd57608433056e51b2c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page