CallScoot exposes a local HTTP API so another app can control calls without embedding telephony logic.
Default bind:
- host:
127.0.0.1 - port:
8788
Service:
systemctl --user status callscoot-api.serviceA separate app can:
- queue an outbound call
- attach dynamic variables / campaign context to the next call
- inspect and patch runtime configuration
- inspect current and past sessions
- stream structured agent events
- inject contextual updates into the active call or a specific session
- hang up the current call
- manage pending outbound call requests
CallScoot stays responsible for:
- Bluetooth call routing
- ElevenAgents session lifecycle
- transcripts and summaries
- stable session IDs and event files
Your app stays responsible for:
- lead lists
- CRM / Sheets / Airtable writes
- campaign logic
- retry policy
- business workflows
curl http://127.0.0.1:8788/v1/healthcurl http://127.0.0.1:8788/v1/statusStatus includes:
- service state
- sanitized config
- resolved telephony backend
sip_statewhen SIP mode is configured- current call
curl http://127.0.0.1:8788/v1/configSensitive values such as sip_password are masked in API responses.
curl -X PATCH http://127.0.0.1:8788/v1/config \
-H 'Content-Type: application/json' \
-d '{
"auto_answer": true,
"auto_answer_delay_sec": 2,
"max_call_duration_sec": 600,
"echo_cancel": false
}'SIP-specific patch example:
curl -X PATCH http://127.0.0.1:8788/v1/config \
-H 'Content-Type: application/json' \
-d '{
"telephony_backend": "sip",
"sip_server": "sip.example.com",
"sip_username": "1001",
"sip_password": "supersecret",
"sip_port": 5060,
"sip_transport": "udp",
"sip_audio_mode": "agent"
}'curl -X POST http://127.0.0.1:8788/v1/outbound-calls \
-H 'Content-Type: application/json' \
-d '{
"number": "+905551112233",
"dynamic_variables": {
"campaign_name": "lead_qualification",
"contact_name": "Efe",
"company_name": "Acme"
},
"metadata": {
"lead_id": "lead-123",
"list_id": "batch-2026-04-11"
},
"ttl_sec": 300
}'This does two things:
- stores a pending request for the next matching call session
- starts the call over the selected telephony backend
If telephony_backend resolves to sip, the response includes via: "sip" and the generated SIP URI. Otherwise CallScoot uses the Android/ADB path.
When the live session starts, the pending request is claimed and injected into the agent as dynamic variables.
curl -X POST http://127.0.0.1:8788/v1/pending-call-requests \
-H 'Content-Type: application/json' \
-d '{
"target_number": "+905551112233",
"dynamic_variables": {
"campaign_name": "renewal_reminder"
},
"metadata": {
"customer_id": "cust-88"
}
}'curl http://127.0.0.1:8788/v1/pending-call-requests/REQUEST_IDcurl -X DELETE http://127.0.0.1:8788/v1/pending-call-requests/REQUEST_IDcurl http://127.0.0.1:8788/v1/current-callcurl 'http://127.0.0.1:8788/v1/calls?limit=20'curl http://127.0.0.1:8788/v1/calls/SESSION_IDcurl http://127.0.0.1:8788/v1/calls/SESSION_ID/eventscurl -N 'http://127.0.0.1:8788/v1/events/stream?session_id=current'Event stream includes items such as:
call_startedconversation_startedtranscript_finalagent_response_startedagent_response_finishedinterruptionclient_errorcall_ended
curl -X POST http://127.0.0.1:8788/v1/current-call/contextual-update \
-H 'Content-Type: application/json' \
-d '{"text":"The CRM says this caller is a warm lead. Keep the conversation under one minute."}'This is non-interrupting guidance for the running agent.
curl -X POST http://127.0.0.1:8788/v1/calls/SESSION_ID/contextual-update \
-H 'Content-Type: application/json' \
-d '{"text":"You already confirmed the callback time. Wrap up the call politely."}'curl -X POST http://127.0.0.1:8788/v1/current-call/user-message \
-H 'Content-Type: application/json' \
-d '{"text":"Ask for a convenient callback time before ending the call."}'curl -X POST http://127.0.0.1:8788/v1/calls/SESSION_ID/user-message \
-H 'Content-Type: application/json' \
-d '{"text":"Ask for an email address before ending."}'curl -X POST http://127.0.0.1:8788/v1/current-call/answercurl -X POST http://127.0.0.1:8788/v1/current-call/hangupA zero-dependency Python helper is included at:
src/callscoot_client.py
A complete sequential lead-calling example is included here:
examples/lead_campaign_app.py
examples/leads.csv.example
examples/minimal_client_app.py
It reads a CSV lead list, queues calls one by one, waits for completion, and writes results back into the same CSV.
from callscoot_client import CallScootClient
client = CallScootClient(base_url="http://127.0.0.1:8788")
client.health()
client.queue_outbound_call(
"+905551112233",
dynamic_variables={
"campaign_name": "survey",
"contact_name": "Efe",
},
metadata={
"row_id": "42",
},
)
session_id = client.wait_for_session_start()
session = client.wait_for_session_end(session_id)
print(session["meta"].get("summary"))If you want a bearer token on the local API, set:
CALLSCOOT_API_TOKEN=your_token_hereThen call with:
-H 'Authorization: Bearer your_token_here'Optional API environment variables:
CALLSCOOT_API_HOST=127.0.0.1
CALLSCOOT_API_PORT=8788
CALLSCOOT_API_TOKEN=If your external client app uses src/callscoot_client.py, it can also use:
CALLSCOOT_API_BASE=http://127.0.0.1:8788The SSE event stream sends heartbeat comments regularly so long-lived consumers can keep the connection open more reliably.