@call-e/calle
v1.0.1
Published
TypeScript server SDK for the CALL-E Developer API.
Readme
@call-e/calle
TypeScript 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
- Developer docs: https://docs.heycall-e.com/
- SDK guide: https://docs.heycall-e.com/#/sdks
- API Reference: https://docs.heycall-e.com/#/api-reference
- Webhooks: https://docs.heycall-e.com/#/webhooks
- Changelog: https://docs.heycall-e.com/#/changelog
- Python server SDK: https://github.com/CALLE-AI/server-sdk-python
SDK surface
client.callscreates, reads, polls and cancels Calls and lists call events.client.goalslists and reads published Goals and runs them with typed results.- The
calleCLI supports common Calls and Goals workflows from scripts and terminals. examples/webhook-server.tsshows how to receive current terminal webhook events.
Install
Install the stable package from npm:
pnpm add @call-e/[email protected]Use a local checkout for development and package smoke tests:
pnpm install
pnpm run validateConfiguration
Create one CalleClient and reuse it for Calls and Goals requests:
| Option | Required | Description |
| --- | --- | --- |
| apiKey | Yes | CALL-E API key. Load it from a server-side secret store or environment variable. |
| baseUrl | No | API base URL. Defaults to https://api.heycall-e.com. |
| fetch | No | Fetch-compatible function for a custom transport or test harness. |
Polling helpers accept interval and timeout options. See the method signatures in your editor and the SDK guide for details.
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
Authorizationheader 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]",
"phone": "[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:
pnpm run example:create-and-waitRun a published Goal and wait for its structured result:
export CALLE_BASE_URL="https://api.heycall-e.com"
export CALLE_GOAL_ID="<PUBLISHED_GOAL_ID>"
export CALLE_EXAMPLE_PHONE="<E164_PHONE>"
export CALLE_GOAL_VARIABLES='{"name":"Alex"}'
export CALLE_IDEMPOTENCY_KEY="<DURABLE_UNIQUE_BUSINESS_KEY>"
pnpm run example:goal-runThe Goal example performs a real call. Use an API key, Goal, phone number, and idempotency key for the selected environment. Persist and reuse the same key when retrying the same logical request.
Run the installed CLI:
npx @call-e/[email protected] calls create \
--api-key "$CALLE_API_KEY" \
--base-url "https://api.heycall-e.com" \
--phone "<AUTHORIZED_E164_PHONE>" \
--region US --locale en-US \
--result-schema '{"type":"object","properties":{"confirmed":{"type":"boolean"}},"required":["confirmed"],"additionalProperties":false}' \
--idempotency-key "hearing-check:example:v1" \
--task "Call this person and ask whether they can hear clearly." \
--wait \
--json--api-key overrides CALLE_API_KEY. Prefer CALLE_API_KEY for shared scripts
because command-line arguments may be stored in shell history.
When --wait is used, progress messages are printed to stderr and the final
call result is printed to stdout. Progress includes call status changes and any
developer events returned by the call events API.
Query an existing call:
npx @call-e/[email protected] calls get call_123 --jsonRun the webhook receiver example:
pnpm run example:webhookThe webhook receiver listens on POST /calle/webhook and processes terminal
event JSON without a webhook secret or signature headers. CALL-E sends the
event only after the post-call outcome and requested structured results are
finalized. Deduplicate side effects with the event id or
CALL-E-Event-Id, and reject events when the required header does not match
the body id. The example defaults to a 10 MiB request-body limit and returns
413 for larger payloads. Set CALLE_WEBHOOK_MAX_BODY_BYTES to match your
provider and ingress limits.
The client.webhooks.verify and signed client.webhooks.unwrap methods
implement the legacy SDK 0.2 contract. 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 { CalleClient } from "@call-e/calle";
const client = new CalleClient({
apiKey: process.env.CALLE_API_KEY!
});
const goal = await client.goals.get("goal_delivery_confirmation");
console.log(goal.title, goal.publishedRunSpec.inputSchema);
const run = await client.goals.runAndWait({
goalId: goal.id,
phone: "+14155550100",
variables: {
customer_name: "Taylor",
order_reference: "ORD-8472",
delivery_window: "July 24, 2:00-4:00 PM"
},
idempotencyKey: "delivery:ORD-8472:confirm-window:v1"
});
if (run.result !== null) {
console.log(run.callId);
console.log(run.result);
} else {
console.error(run.error);
}Run the same published Goal through the CLI:
npx @call-e/[email protected] goals run \
--goal-id "goal_delivery_confirmation" \
--phone "<AUTHORIZED_E164_PHONE>" \
--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" \
--wait \
--jsonPersist the idempotency key before the first request and reuse it for network
retries. waitForResult 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.
const call = await client.calls.createAndWait({
task: "Ask whether Friday lunch is confirmed.",
phone: "<AUTHORIZED_E164_PHONE>", region: "US", locale: "en-US",
resultSchema: {
type: "object", additionalProperties: false, required: ["answer"],
properties: { answer: { type: "string", enum: ["yes", "no", "unknown"] } }
}
}, { idempotencyKey: "lunch:friday:confirmation:v1" });
if (call.error === null) console.log(call.result);
else console.log(call.error);
// Cancel a queued call before provider submission:
// await client.calls.cancel(callId);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.
Turn keys retain the HTTP names. 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 typed errors for API responses, authentication, rate limits, polling timeouts, and missing response bodies:
import { CalleAPIError, CalleClient } from "@call-e/calle";
const client = new CalleClient({ apiKey: process.env.CALLE_API_KEY! });
try {
await client.calls.get("call_123");
} catch (error) {
if (error instanceof CalleAPIError) {
console.error(error.status, error.code, error.details);
}
throw error;
}Release
This repository publishes the npm package @call-e/calle.
Merging to main runs CI and does not publish the package. Publishing a GitHub
Release with a matching vX.Y.Z tag starts the npm release workflow. Manual
workflow runs are dry runs only. 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.
Project Documents
License
This project is licensed under the MIT License. The same license
applies to the published npm packages @call-e/[email protected] and
@call-e/[email protected].
