Telnyx AI Missions
Track multi-step agent activities using the Telnyx AI Missions API. Create voice/SMS assistants, schedule calls, and retrieve conversation insights.
🛑 GUARDRAILS — Actions Requiring Explicit User Permission
The following actions are NEVER allowed without explicit user approval. Do not proceed with any of these — even if the mission plan implies them — until the user has reviewed and confirmed.
These guardrails apply to all contexts: interactive sessions, cron-triggered runs, sub-agent executions, and any automated workflow that uses this skill.
Prohibited Without Permission
Remove a connection from a phone number — Never unassign or change the connection profile on a phone number without user review. This can break live call routing.
Create, edit, or delete an AI assistant — Assistants are shared resources. Creating new ones, modifying instructions/tools/voice on existing ones, or deleting them requires explicit approval. (Reusing an existing assistant as-is is fine.)
Create or edit TeXML apps or other connections — Missions should never need to create or modify TeXML applications, SIP connections, FQDN connections, or any other connection type. If a mission plan seems to require this, stop and ask the user — the approach is wrong.
Schedule a cron job — Never create, modify, or enable a cron job (OpenClaw cron, system cron, or any scheduled automation) without user review. This includes cron jobs for polling, retries, or follow-up actions.
Enforcement
- Before executing any of the above: pause, describe what you intend to do and why, and wait for explicit approval.
- If running via cron or automation: the cron-triggered agent must also follow these guardrails. Automation does not grant implicit permission. If a guardrailed action is needed, notify the user and wait — do not proceed unattended.
- If in doubt: ask. It is always better to pause and confirm than to take an irreversible action.
Setup
The Python script telnyx_api.py handles all API calls:
# Set your API key
export TELNYX_API_KEY="your_key_here"
# Run commands using the script
python3 {baseDir}/scripts/telnyx_api.py <command> [args...]
# Or create an alias for convenience
alias missions="python3 {baseDir}/scripts/telnyx_api.py"
Note: All command examples in this document use python telnyx_api.py for brevity. Replace with the full path python3 {baseDir}/scripts/telnyx_api.py or use the alias above.
This skill enables you to track your work using the Telnyx AI Missions API, including making phone calls and sending SMS messages through AI assistants.
⚠️ CRITICAL: SAVE STATE FREQUENTLY ⚠️
You MUST save your progress after EVERY significant action. If the session crashes or restarts, unsaved work is LOST.
Two-Layer Persistence: Memory + Events
Always save to BOTH:
- Local Memory (
.missions_state.json) - Fast, survives restarts - Events API (cloud) - Permanent audit trail, survives local file loss
When to Save (After EVERY action!)
| Action | Save Memory | Log Event |
|---|---|---|
| Web search returns results | ✅ append-memory | ✅ log-event (tool_call) |
| Found a contractor/lead | ✅ append-memory | ✅ log-event (custom) |
| Created assistant | ✅ save-memory | ✅ log-event (custom) |
| Assigned phone number | ✅ save-memory | ✅ log-event (custom) |
| Scheduled a call/SMS | ✅ append-memory | ✅ log-event (custom) |
| Call completed | ✅ save-memory | ✅ log-event (custom) |
| Got quote/insight | ✅ save-memory | ✅ log-event (custom) |
| Made a decision | ✅ save-memory | ✅ log-event (message) |
| Step started | ✅ save-memory | ✅ update-step (in_progress) + log-event (step_started) |
| Step completed | ✅ save-memory | ✅ update-step (completed) + log-event (step_completed) |
| Step failed | ✅ save-memory | ✅ update-step (failed) + log-event (error) |
| Error occurred | ✅ save-memory | ✅ log-event (error) |
Memory Commands (Local Backup)
# Save a single value
python telnyx_api.py save-memory "<slug>" "key" '{"data": "value"}'
# Append to a list (great for collecting multiple items)
python telnyx_api.py append-memory "<slug>" "contractors" '{"name": "ABC Co", "phone": "+1234567890"}'
# Retrieve memory
python telnyx_api.py get-memory "<slug>" # Get all memory
python telnyx_api.py get-memory "<slug>" "key" # Get specific key
Event Commands (Cloud Backup)
# Log an event (step_id is REQUIRED - links event to a plan step)
python telnyx_api.py log-event <mission_id> <run_id> <type> "<summary>" <step_id> '[payload_json]'
# Event types: tool_call, custom, message, error, step_started, step_completed
# step_id: Use the step_id from your plan (e.g., "research", "setup", "calls")
# Use "-" if event doesn't belong to a specific step
Example: Complete Save Pattern
After finding a contractor via web search, do BOTH:
# 1. Save to local memory (fast recovery)
python telnyx_api.py append-memory "find-window-washers" "contractors_found" '{"name": "ABC Cleaning", "phone": "+13125551234", "source": "google search"}'
# 2. Log to events API with step_id (permanent cloud record linked to plan step)
python telnyx_api.py log-event "$MISSION_ID" "$RUN_ID" custom "Found contractor: ABC Cleaning +13125551234" "research" '{"contractor": "ABC Cleaning", "phone": "+13125551234", "source": "google search"}'
After scheduling a call:
# 1. Local memory
python telnyx_api.py append-memory "find-window-washers" "calls_scheduled" '{"event_id": "evt_123", "contractor": "ABC Cleaning", "time": "2024-12-01T15:00:00Z"}'
# 2. Cloud event with step_id
python telnyx_api.py log-event "$MISSION_ID" "$RUN_ID" custom "Scheduled call to ABC Cleaning for 3:00 PM" "calls" '{"scheduled_event_id": "evt_123", "contractor": "ABC Cleaning", "scheduled_for": "2024-12-01T15:00:00Z"}'
After getting a quote from a call:
# 1. Local memory
python telnyx_api.py save-memory "find-window-washers" "quotes" '{"ABC Cleaning": {"amount": 350, "available": "next week"}}'
# 2. Cloud event with step_id
python telnyx_api.py log-event "$MISSION_ID" "$RUN_ID" custom "Call completed: ABC Cleaning quoted $350" "calls" '{"contractor": "ABC Cleaning", "quote": 350, "availability": "next week", "conversation_id": "conv_xyz"}'
Best Practices
- Save IMMEDIATELY - Don't wait, don't batch
- Save to BOTH - Memory (local) AND Events (cloud)
- Be verbose - More data saved = easier recovery
- Include context - Timestamps, sources, IDs
- Save partial results - Something is better than nothing
- Save before risky operations - Before long API calls or waits
When to Use This Skill
This skill has two modes: full missions (tracked, multi-step) and simple calls (one-off, no mission overhead). Pick the right one.
Use a Full Mission When:
- The task involves multiple calls or SMS (batch outreach, surveys, sweeps)
- You need a complete audit trail with events, plans, and state tracking
- The task is multi-step and takes significant effort across phases
- Retries and failure tracking matter
- You need to compare results across multiple calls
Examples:
- "Find me window washing contractors in Chicago, call them and negotiate rates"
- "Contact all leads in this list and schedule demos"
- "Call 10 weather stations and find the hottest one"
Do NOT Use a Mission When:
- The task is a single outbound call — just create an assistant (or reuse one) and schedule the call directly
- It's a one-off SMS — schedule it and done
- The task doesn't need tracking, plans, or state recovery
- You'd be creating a mission with one step and one call — that's overengineering
For simple calls, just:
# Reuse or create an assistant
python telnyx_api.py list-assistants --name=<relevant>
# Schedule the call
python telnyx_api.py schedule-call <assistant_id> <to> <from> <datetime> <mission_id> <run_id> <step_id>
# Poll for completion
python telnyx_api.py get-event <assistant_id> <event_id>
# Get insights
python telnyx_api.py get-insights <conversation_id>
No mission, no run, no plan. Keep it simple.
Required Setup
The Python script telnyx_api.py handles all API calls. Check that TELNYX_API_KEY environment variable is set:
python telnyx_api.py check-key
State Persistence
The script automatically manages state in .missions_state.json. This survives restarts and supports multiple concurrent missions.
State Commands
# List all active missions
python telnyx_api.py list-state
# Get state for a specific mission
python telnyx_api.py get-state "find-window-washing-contractors"
# Remove a mission from state
python telnyx_api.py remove-state "find-window-washing-contractors"
Core Workflow
Phase 1: Initialize Tracking
Step 1.1: Create a Mission
python telnyx_api.py create-mission "Brief descriptive name" "Full description of the task"
Save the returned mission_id - you'll need it for all subsequent calls.
Step 1.2: Start a Run
python telnyx_api.py create-run <mission_id> '{"original_request": "The exact user request", "context": "Any relevant context"}'
Save the returned run_id.
Step 1.3: Create a Plan
Before executing, outline your plan:
python telnyx_api.py create-plan <mission_id> <run_id> '[
{"step_id": "step_1", "description": "Research contractors online", "sequence": 1},
{"step_id": "step_2", "description": "Create voice agent for calls", "sequence": 2},
{"step_id": "step_3", "description": "Schedule calls to each contractor", "sequence": 3},
{"step_id": "step_4", "description": "Monitor call completions", "sequence": 4},
{"step_id": "step_5", "description": "Analyze results and select best options", "sequence": 5}
]'
Step 1.4: Set Run to Running
python telnyx_api.py update-run <mission_id> <run_id> running
High-Level Alternative: Initialize Everything at Once
Use the init command to create mission, run, plan, and set status in one step:
python telnyx_api.py init "Find window washing contractors" "Find contractors in Chicago, call them, negotiate rates" "User wants window washing quotes" '[
{"step_id": "research", "description": "Find contractors online", "sequence": 1},
{"step_id": "setup", "description": "Create voice agent", "sequence": 2},
{"step_id": "calls", "description": "Schedule and make calls", "sequence": 3},
{"step_id": "analyze", "description": "Analyze results", "sequence": 4}
]'
This also automatically resumes if a mission with the same name already exists.
Phase 2: Voice/SMS Agent Setup
When your task requires making calls or sending SMS, create an AI assistant first.
Step 2.1: Create a Voice/SMS Assistant
For phone calls:
python telnyx_api.py create-assistant "Contractor Outreach Agent" "You are calling on behalf of [COMPANY]. Your goal is to [SPECIFIC GOAL]. Be professional and concise. Collect: [WHAT TO COLLECT]. If they cannot talk now, ask for a good callback time." "Hi, this is an AI assistant calling on behalf of [COMPANY]. Is this [BUSINESS NAME]? I am calling to inquire about your services. Do you have a moment?" '["telephony"]'
For SMS:
python telnyx_api.py create-assistant "SMS Outreach Agent" "You send SMS messages to collect information. Keep messages brief and professional." "Hi! I am reaching out on behalf of [COMPANY] regarding [PURPOSE]. Could you please reply with [REQUESTED INFO]?" '["messaging"]'
Save the returned assistant_id.
Step 2.2: Find and Assign a Phone Number
2.2.1: List Available Phone Numbers
python telnyx_api.py list-phones --available
Or get the first available one directly:
python telnyx_api.py get-available-phone
If no phone numbers are available, STOP and inform the user:
"No available phone numbers found. You need to purchase phone numbers from Telnyx at https://portal.telnyx.com before I can make calls."
2.2.2: Get Assistant's Connection ID
# For voice calls
python telnyx_api.py get-connection-id <assistant_id> telephony
# For SMS
python telnyx_api.py get-connection-id <assistant_id> messaging
2.2.3: Assign Phone Number to Assistant
# For voice calls
python telnyx_api.py assign-phone <phone_number_id> <connection_id> voice
# For SMS
python telnyx_api.py assign-phone <phone_number_id> <connection_id> sms
High-Level Alternative: Setup Agent in One Step
Use the setup-agent command to create assistant and assign phone number:
python telnyx_api.py setup-agent "find-window-washing-contractors" "Contractor Caller" "You are calling to get quotes for commercial window washing. Ask about: rates per floor, availability, insurance. Be professional." "Hi, I am calling to inquire about your commercial window washing services. Do you have a moment to discuss rates?"
This automatically:
- Creates the assistant with telephony features
- Links the agent to the mission run (if mission_id and run_id are in state)
- Finds an available phone number
- Assigns it to the assistant
- Saves all IDs to the state file
Step 2.3: Link Agent to Mission Run
IMPORTANT: After creating an assistant, you MUST link it to the mission run. This allows the system to track which agents are working on which missions.
If using setup-agent command: Linking is done automatically when mission_id and run_id are in the state.
If setting up manually:
python telnyx_api.py link-agent <mission_id> <run_id> <assistant_id>
You can also list and unlink agents:
# List all agents linked to a run
python telnyx_api.py list-linked-agents <mission_id> <run_id>
# Unlink an agent from a run
python telnyx_api.py unlink-agent <mission_id> <run_id> <assistant_id>
Step 2.4: Log the Setup
python telnyx_api.py log-event <mission_id> <run_id> custom "Created voice assistant and assigned phone number" "setup" '{"assistant_id": "<assistant_id>", "phone_number": "+15551234567", "type": "telephony"}'
Phase 3: Research & Data Gathering
Search for the information you need (contractors, leads, etc.):
- Use web search tools if available
- Use any specialized tools provided for the task
- Log each search as an event with step_id
python telnyx_api.py log-event <mission_id> <run_id> tool_call "Searching for window washing contractors in Chicago" "research" '{"tool": "WebSearch", "query": "commercial window washing contractors Chicago"}'
Phase 4: Scheduling Calls/SMS
Business Hours Consideration
CRITICAL: Before scheduling calls, consider business hours:
- Typical business hours: 9 AM - 5 PM local time
- If current time is outside business hours, schedule for next business day
scheduled_at_fixed_datetimemust be in the future (at least 1 minute from now)
Step 4.1: Schedule a Phone Call
python telnyx_api.py schedule-call <assistant_id> "+15551234567" "+15559876543" "2024-12-01T14:30:00Z" <mission_id> <run_id> <step_id>
Save the returned scheduled_event_id.
Step 4.2: Schedule an SMS
python telnyx_api.py schedule-sms <assistant_id> "+15551234567" "+15559876543" "2024-12-01T14:30:00Z" "Hi! I am reaching out on behalf of [COMPANY] to inquire about your window cleaning rates for commercial buildings. Could you share your pricing?" <mission_id> <run_id> <step_id>
Step 4.3: Log Each Scheduled Event
python telnyx_api.py log-event <mission_id> <run_id> custom "Scheduled call to ABC Window Cleaning for 2:30 PM" "calls" '{"scheduled_event_id": "<event_id>", "contractor": "ABC Window Cleaning", "phone": "+15551234567", "scheduled_for": "2024-12-01T14:30:00Z"}'
Phase 5: Monitoring Call Completion
After a call is scheduled, you need to poll for completion.
Step 5.1: Check Scheduled Event Status
python telnyx_api.py get-event <assistant_id> <scheduled_event_id>
Event Status Values
The event-level status tracks the overall lifecycle:
| Status | Meaning | Action |
|---|---|---|
pending |
Waiting for scheduled time | Wait and check again later |
in_progress |
Call/SMS in progress | Check again in a few minutes |
completed |
Finished successfully | Get conversation_id, fetch insights |
failed |
Failed after retries | Consider rescheduling |
Call Status Values (Phone Calls Only)
The call_status field provides the telephony-level outcome. This is the most important field for deciding what to do next.
| call_status | Meaning | Action |
|---|---|---|
ringing |
Phone is ringing, not yet answered | Still in progress — wait and poll again in 1-2 minutes |
in-progress |
Call is active, conversation ongoing | Still in progress — poll again in 2-3 minutes |
completed |
Call connected and finished normally | Success — get conversation_id, fetch insights |
no-answer |
Phone rang but nobody picked up | Retryable — reschedule for a different time |
busy |
Line is busy | Retryable — reschedule in 10-15 minutes, line may free up quickly |
canceled |
Call was canceled | Check if you canceled it; if not, may need to reschedule |
failed |
Call failed (network/system error) | Retryable — reschedule after a short backoff (5-10 minutes) |
Step 5.2: Polling Strategy
When to start polling: A few minutes after scheduled_at_fixed_datetime
Polling intervals based on call_status:
ringing→ poll again in 1-2 minutes (call may connect any moment)in-progress→ poll again in 2-3 minutes (conversation is happening)pending(event status) → poll every 5 minutes until scheduled time passesno-answer/busy/failed→ stop polling, handle retry immediatelycompleted→ done, proceed to fetch insights
Timeout: If still ringing or in-progress after 30 minutes, treat as failed.
Step 5.3: Handle Retryable Call Statuses
When call_status is no-answer, busy, or failed, the call can be retried:
- Update the call tracker with the failure reason
- Check retry count — by default, retry up to 3 times (unless user specifies otherwise)
- Schedule a retry at a different time based on the failure type:
busy→ retry in 10-15 minutes (line may free up)no-answer→ retry in 30 minutes to 2 hours (try a different time of day)failed→ retry in 5-10 minutes (transient error)
- Log the failure and retry as events
# Update tracker
python telnyx_api.py save-memory "<slug>" "call_tracker" '{"+15551234567": {"status": "no_answer", "attempts": 1, "call_status": "no-answer", "next_retry": "2024-12-02T10:00:00Z"}}'
# Log the failure
python telnyx_api.py log-event "$MISSION_ID" "$RUN_ID" custom "Call not answered (busy), scheduling retry #2" "calls" '{"phone": "+15551234567", "call_status": "busy", "attempt": 1}'
# Schedule retry
python telnyx_api.py schedule-call <assistant_id> "+15551234567" "+15559876543" "2024-12-02T10:00:00Z" <mission_id> <run_id> <step_id>
Phase 6: Getting Conversation Insights
Once a call completes and you have a conversation_id, retrieve the conversation insights.
IMPORTANT: Always use insights to get the call summary. Do NOT fetch raw conversation messages - insights provide a structured summary of the conversation outcome.
Step 6.1: Get Conversation Insights
python telnyx_api.py get-insights <conversation_id>
Step 6.2: Poll Until Insight is Complete
The insight may not be immediately ready after the call ends. You must poll until the insight status is "completed".
Polling strategy:
- Check immediately after getting the
conversation_id - If status is NOT "completed", wait 10 seconds and retry
- Continue polling until status is "completed" or 20 minutes have passed
- Only use the insight data when status is "completed"
Example polling flow:
# First attempt
python telnyx_api.py get-insights "conv_xyz"
# Output: Insight status: in_progress
# Wait 10 seconds, try again
python telnyx_api.py get-insights "conv_xyz"
# Output: Insight status: in_progress
# Wait 10 seconds, try again
python telnyx_api.py get-insights "conv_xyz"
# Output: Insight: Customer quoted $350 for a 10-story building...
Step 6.3: Rename the Conversation
By default, all conversations are named "Voice Assistant Conversation" which is useless for reviewing in the portal. Rename each conversation with a meaningful label after it completes:
python telnyx_api.py rename-conversation "<conv_id>" "Call 1: ABC Window Cleaning - $350/visit"
Best practice: Include the call sequence number, target name, and key outcome in the name. This makes conversations instantly identifiable when browsing the mission in the Telnyx portal.
Step 6.4: Log the Insight
python telnyx_api.py log-event <mission_id> <run_id> custom "Call completed with ABC Window Cleaning - quoted $350" "calls" '{"conversation_id": "<conv_id>", "contractor": "ABC Window Cleaning", "outcome": "success", "quote": "$350", "availability": "next week", "notes": "Willing to negotiate for recurring contracts"}'
Phase 7: Complete the Mission
⚠️ MANDATORY Completion Checklist
Every mission MUST complete ALL of these before it can be considered done. Skipping any of these leaves the mission in a broken state in the Telnyx portal.
| # | Action | Command | Why |
|---|---|---|---|
| 1 | Update ALL plan step statuses | update-step <mid> <rid> <step_id> completed |
Steps show in portal — "pending" means it looks unfinished |
| 2 | Log events for every completed call | log-event ... custom "Call completed" <step_id> '{"conversation_id": "..."}' |
Creates audit trail linking conversations to the mission |
| 3 | Set run result_summary | Included in complete or update-run |
Human-readable summary visible in portal |
| 4 | Set run result_payload | Included in complete or update-run |
Structured data for programmatic consumption |
| 5 | Mark run as succeeded/failed | complete or update-run <mid> <rid> succeeded |
Closes the run |
The complete command handles #3, #4, and #5 in one call — but you still need to do #1 and #2 yourself.
# 1. Update every step status (do this THROUGHOUT the mission, not just at the end)
python telnyx_api.py update-step <mission_id> <run_id> "setup" "completed"
python telnyx_api.py update-step <mission_id> <run_id> "calls" "completed"
python telnyx_api.py update-step <mission_id> <run_id> "analyze" "completed"
# 2. Complete the run with summary and payload
python telnyx_api.py complete "<slug>" <mission_id> <run_id> \
"Contacted 5 contractors, received 4 quotes. Best: ABC Cleaning ($350)" \
'{"contractors_contacted": 5, "quotes_received": 4, "recommended": [{"name": "ABC Cleaning", "quote": 350}]}'
Common mistake: Logging step_completed events but NOT calling update-step. These are separate — events are the audit log, step status is the progress tracker. You need BOTH.
Step 7.1: Analyze Results
After all calls complete:
- Compare quotes and outcomes
- Select best options based on criteria
- Prepare summary for user
Step 7.2: Complete the Run
Use the complete command to set result_summary, result_payload, mark the run as succeeded, and clean up state in one step:
python telnyx_api.py complete "find-window-washing-contractors" <mission_id> <run_id> "Contacted 5 contractors, received 4 quotes. Best options: ABC Cleaning ($350) and XYZ Windows ($380)." '{"contractors_contacted": 5, "quotes_received": 4, "recommended": [{"name": "ABC Cleaning", "quote": 350}, {"name": "XYZ Windows", "quote": 380}]}'
Or use update-run directly with all fields:
python telnyx_api.py update-run <mission_id> <run_id> succeeded "Human-readable summary here" '{"structured": "payload"}'
The complete command also removes the mission from the state file.
Event Logging Reference
Log EVERY action as an event for complete audit trail. Events are stored in the cloud and provide permanent backup even if local files are lost.
CRITICAL: Update Step Status (Not Just Events!)
You MUST update the plan step status via update-step when starting or completing each step. Logging events alone does NOT change the step status — the client tracks progress by looking at step statuses, not events.
# When STARTING a step:
python telnyx_api.py update-step "$MISSION_ID" "$RUN_ID" "research" "in_progress"
python telnyx_api.py log-event "$MISSION_ID" "$RUN_ID" step_started "Starting: Research contractors" "research"
# When COMPLETING a step:
python telnyx_api.py update-step "$MISSION_ID" "$RUN_ID" "research" "completed"
python telnyx_api.py log-event "$MISSION_ID" "$RUN_ID" step_completed "Completed: Research contractors" "research"
# When a step FAILS:
python telnyx_api.py update-step "$MISSION_ID" "$RUN_ID" "calls" "failed"
python telnyx_api.py log-event "$MISSION_ID" "$RUN_ID" error "Failed: Could not reach any contractors" "calls"
# To SKIP a step:
python telnyx_api.py update-step "$MISSION_ID" "$RUN_ID" "setup" "skipped"
Always call update-step BEFORE log-event — this ensures the step status is correct even if the event logging fails.
IMPORTANT: step_id is Required
step_id is a required parameter - it links events to your plan steps, enabling tracking of which activities belong to which phase.
# With step_id (links to plan step)
python telnyx_api.py log-event "$MISSION_ID" "$RUN_ID" custom "Found contractor" "research" '{"name": "ABC"}'
# Use "-" if event doesn't belong to a specific step
python telnyx_api.py log-event "$MISSION_ID" "$RUN_ID" custom "General note" "-" '{"note": "value"}'
The step_id should match one of the step_id values from your plan (e.g., "research", "setup", "calls", "analyze").
| Action | Step Status Update | Event Type | step_id | Example Summary |
|---|---|---|---|---|
| Starting a plan step | update-step ... in_progress |
step_started |
step_id | "Starting: Research contractors" |
| Completing a step | update-step ... completed |
step_completed |
step_id | "Completed: Research contractors" |
| Step failed | update-step ... failed |
error |
step_id | "Failed: Could not reach contractors" |
| Web search | — | tool_call |
"research" | "Searching for window cleaning contractors" |
| Creating assistant | — | custom |
"setup" | "Created voice assistant: ast_123" |
| Scheduling call | — | custom |
"calls" | "Scheduled call to ABC for 2:30 PM" |
| Call completed | — | custom |
"calls" | "Call completed with ABC - got quote $350" |
| Call failed | — | error |
"calls" | "Call to XYZ not answered after 3 attempts" |
| Decision made | — | message |
"analyze" | "Selected ABC and XYZ as top choices" |
Quick Reference: All Commands
# Check setup
python telnyx_api.py check-key
# Missions
python telnyx_api.py create-mission <name> <instructions>
python telnyx_api.py get-mission <mission_id>
python telnyx_api.py list-missions
# Runs
python telnyx_api.py create-run <mission_id> <input_json>
python telnyx_api.py get-run <mission_id> <run_id>
python telnyx_api.py update-run <mission_id> <run_id> <status>
python telnyx_api.py list-runs <mission_id>
# Plan
python telnyx_api.py create-plan <mission_id> <run_id> <steps_json>
python telnyx_api.py get-plan <mission_id> <run_id>
python telnyx_api.py update-step <mission_id> <run_id> <step_id> <status>
# status: pending, in_progress, completed, skipped, failed
# Events (step_id is REQUIRED - use "-" if no specific step)
python telnyx_api.py log-event <mission_id> <run_id> <type> <summary> <step_id> [payload_json]
python telnyx_api.py list-events <mission_id> <run_id>
# Assistants
python telnyx_api.py list-assistants [--name=<filter>] [--page=<n>] [--size=<n>]
python telnyx_api.py create-assistant <name> <instructions> <greeting> [options_json]
python telnyx_api.py get-assistant <assistant_id>
python telnyx_api.py update-assistant <assistant_id> <updates_json>
python telnyx_api.py get-connection-id <assistant_id> [telephony|messaging]
# Phone Numbers
python telnyx_api.py list-phones [--available]
python telnyx_api.py get-available-phone
python telnyx_api.py assign-phone <phone_id> <connection_id> [voice|sms]
# Scheduled Events
python telnyx_api.py schedule-call <assistant_id> <to_phone> <from_phone> <datetime> <mission_id> <run_id> [step_id] [dynamic_variables_json]
python telnyx_api.py schedule-sms <assistant_id> <to_phone> <from_phone> <datetime> <text> [mission_id] [mission_run_id] [step_id] [dynamic_variables_json]
python telnyx_api.py get-event <assistant_id> <event_id>
python telnyx_api.py cancel-scheduled-event <assistant_id> <event_id>
python telnyx_api.py list-events-assistant <assistant_id>
# Insights (conversation results - POLL until status is "completed"!)
python telnyx_api.py get-insights <conversation_id>
python telnyx_api.py rename-conversation <conversation_id> <name>
# Insight Templates (CRUD)
python telnyx_api.py create-insight <name> <instructions> [options_json] # options: json_schema, webhook
python telnyx_api.py get-insight <insight_id>
python telnyx_api.py list-insights
python telnyx_api.py update-insight <insight_id> <updates_json>
# Insight Groups
python telnyx_api.py create-insight-group <name> [options_json] # options: description, webhook
python telnyx_api.py get-insight-group <group_id>
python telnyx_api.py list-insight-groups
python telnyx_api.py update-insight-group <group_id> <updates_json>
python telnyx_api.py assign-insight <group_id> <insight_id>
python telnyx_api.py unassign-insight <group_id> <insight_id>
# Mission Run Agents (linking agents to runs)
python telnyx_api.py link-agent <mission_id> <run_id> <telnyx_agent_id>
python telnyx_api.py list-linked-agents <mission_id> <run_id>
python telnyx_api.py unlink-agent <mission_id> <run_id> <telnyx_agent_id>
# State Management
python telnyx_api.py list-state
python telnyx_api.py get-state <slug>
python telnyx_api.py remove-state <slug>
# Memory (SAVE OFTEN!)
python telnyx_api.py save-memory <slug> <key> <value_json>
python telnyx_api.py get-memory <slug> [key]
python telnyx_api.py append-memory <slug> <key> <item_json>
# High-Level Workflows
python telnyx_api.py init <name> <instructions> <request> [steps_json]
python telnyx_api.py setup-agent <slug> <name> <instructions> <greeting>
python telnyx_api.py complete <slug> <mission_id> <run_id> <summary> [payload_json]
Complete Example: Window Washing Contractors
# 1. Initialize the mission (creates mission, run, plan, sets to running)
python telnyx_api.py init "Find window washing contractors" \
"Find contractors in Chicago, call them, negotiate rates, select best two" \
"Find me window washing contractors in Chicago" \
'[{"step_id": "research", "description": "Find contractors online", "sequence": 1}, {"step_id": "setup", "description": "Create voice agent", "sequence": 2}, {"step_id": "calls", "description": "Schedule and make calls", "sequence": 3}, {"step_id": "analyze", "description": "Analyze results", "sequence": 4}]'
# Output: Created mission: mis_abc123
# Created run: run_def456
# 2. Get the mission slug and IDs from state
python telnyx_api.py get-state "find-window-washing-contractors"
# 3. Mark research step as in_progress and start working
python telnyx_api.py update-step "mis_abc123" "run_def456" "research" "in_progress"
python telnyx_api.py log-event "mis_abc123" "run_def456" step_started "Starting: Find contractors online" "research"
# 4. Setup voice agent (creates assistant, links to run, assigns phone number)
python telnyx_api.py update-step "mis_abc123" "run_def456" "setup" "in_progress"
python telnyx_api.py setup-agent "find-window-washing-contractors" \
"Contractor Caller" \
"You are calling to get quotes for commercial window washing. Ask about: rates per floor, availability, insurance. Be professional." \
"Hi, I am calling to inquire about your commercial window washing services. Do you have a moment to discuss rates?"
# Output: Created assistant: ast_xyz789
# Linked agent ast_xyz789 to run run_def456
# Found available: +15559876543
# Assigned phone number 123456
python telnyx_api.py update-step "mis_abc123" "run_def456" "setup" "completed"
python telnyx_api.py log-event "mis_abc123" "run_def456" step_completed "Completed: Voice agent setup" "setup"
# 5. Get agent phone from state
AGENT_PHONE=$(python telnyx_api.py get-state "find-window-washing-contractors" | python -c "import sys,json; print(json.load(sys.stdin).get('agent_phone',''))")
ASSISTANT_ID=$(python telnyx_api.py get-state "find-window-washing-contractors" | python -c "import sys,json; print(json.load(sys.stdin).get('assistant_id',''))")
# 6. After research, SAVE to memory AND log events with step_id (CRITICAL!)
python telnyx_api.py append-memory "find-window-washing-contractors" "contractors_found" '{"name": "ABC Cleaning", "phone": "+13125551234", "source": "web search"}'
python telnyx_api.py log-event "mis_abc123" "run_def456" custom "Found contractor: ABC Cleaning" "research" '{"name": "ABC Cleaning", "phone": "+13125551234"}'
python telnyx_api.py append-memory "find-window-washing-contractors" "contractors_found" '{"name": "XYZ Windows", "phone": "+13125555678", "source": "web search"}'
python telnyx_api.py log-event "mis_abc123" "run_def456" custom "Found contractor: XYZ Windows" "research" '{"name": "XYZ Windows", "phone": "+13125555678"}'
# 7. Complete research step, start calls step
python telnyx_api.py update-step "mis_abc123" "run_def456" "research" "completed"
python telnyx_api.py log-event "mis_abc123" "run_def456" step_completed "Completed: Found 2 contractors" "research"
python telnyx_api.py update-step "mis_abc123" "run_def456" "calls" "in_progress"
python telnyx_api.py log-event "mis_abc123" "run_def456" step_started "Starting: Schedule calls" "calls"
# 8. Schedule calls
python telnyx_api.py schedule-call "$ASSISTANT_ID" "+13125551234" "$AGENT_PHONE" "2024-12-01T15:00:00Z" "$MISSION_ID" "$RUN_ID" "$STEP_ID"
# Output: Scheduled call: evt_abc123
# 9. SAVE scheduled event to memory AND log event with step_id (CRITICAL!)
python telnyx_api.py append-memory "find-window-washing-contractors" "calls_scheduled" '{"event_id": "evt_abc123", "contractor": "ABC Cleaning", "scheduled_for": "2024-12-01T15:00:00Z"}'
python telnyx_api.py log-event "mis_abc123" "run_def456" custom "Scheduled call to ABC Cleaning for 3:00 PM" "calls" '{"scheduled_event_id": "evt_abc123", "contractor": "ABC Cleaning"}'
# 10. Poll for completion (after scheduled time)
python telnyx_api.py get-event "$ASSISTANT_ID" "evt_abc123"
# Output: Status: completed, conversation_id: conv_xyz
# 11. Get insights - POLL UNTIL STATUS IS "completed"
python telnyx_api.py get-insights "conv_xyz"
# Output: Insight status: in_progress
# (wait 10 seconds and retry)
python telnyx_api.py get-insights "conv_xyz"
# Output: Insight status: in_progress
# (wait 10 seconds and retry)
python telnyx_api.py get-insights "conv_xyz"
# Output: Insight: Customer quoted $350 for a 10-story building. Available next week.
# (status is now "completed" - proceed with the insight data)
# 12. SAVE call results to memory AND log event with step_id (CRITICAL!)
python telnyx_api.py save-memory "find-window-washing-contractors" "call_results" '{"ABC Cleaning": {"status": "completed", "conversation_id": "conv_xyz", "quote": 350, "availability": "next week"}}'
python telnyx_api.py log-event "mis_abc123" "run_def456" custom "Call completed: ABC Cleaning quoted $350, available next week" "calls" '{"contractor": "ABC Cleaning", "quote": 350, "conversation_id": "conv_xyz"}'
# 13. Complete calls step, start analyze step
python telnyx_api.py update-step "mis_abc123" "run_def456" "calls" "completed"
python telnyx_api.py log-event "mis_abc123" "run_def456" step_completed "Completed: All calls done" "calls"
python telnyx_api.py update-step "mis_abc123" "run_def456" "analyze" "in_progress"
python telnyx_api.py log-event "mis_abc123" "run_def456" step_started "Starting: Analyze results" "analyze"
# 14. Complete the mission (mark analyze step done first)
python telnyx_api.py update-step "mis_abc123" "run_def456" "analyze" "completed"
python telnyx_api.py log-event "mis_abc123" "run_def456" step_completed "Completed: Analysis done" "analyze"
python telnyx_api.py complete "find-window-washing-contractors" "mis_abc123" "run_def456" \
"Found 2 best contractors: ABC ($350) and XYZ ($380)" \
'{"recommended": ["ABC Cleaning", "XYZ Windows"]}'
# Output: Updated run run_def456: succeeded
# Mission 'find-window-washing-contractors' completed successfully
⚠️ BEFORE CREATING ANYTHING: Review Existing Resources
Always check what already exists before creating new assistants, insights, or insight groups. Reuse is better than duplication.
Pre-flight Checklist
Run these commands at the start of every mission to inventory what's available:
# 1. Search for existing assistants by name — maybe one already fits your use case
python telnyx_api.py list-assistants --name=Weather
python telnyx_api.py list-assistants # or list all (paginated)
python telnyx_api.py list-assistants --page=2 # next page
# 2. List existing insight templates — reuse structured insights across missions
python telnyx_api.py list-insights
# 3. List existing insight groups — you may only need to add an insight to an existing group
python telnyx_api.py list-insight-groups
# 4. List available phone numbers — check what's already assigned vs free
python telnyx_api.py list-phones --available
All list commands are paginated. If you have many resources, page through with --page=N. The assistant name filter does substring matching — use it to quickly find relevant assistants instead of scrolling through pages.
Decision Flow
⚠️ CRITICAL: Reuse Without Modification
The rule is: reuse existing resources IF you can use them as-is. Do NOT modify existing assistants, insights, or insight groups that may be in use by other missions or users. Editing a shared resource (e.g., changing an assistant's instructions or an insight's schema) can silently break unrelated workflows that depend on the current configuration.
Safe to reuse without modification:
- An existing assistant whose instructions, tools, voice, and settings already match your needs exactly
- An existing insight template whose schema/instructions already extract what you need
- The default "Summary" insight (always reuse this — never recreate it)
- An existing insight group that already contains the insights you need
When to create new instead of reusing:
- You need different instructions, tools, voice, or model → create a new assistant
- You need a different extraction schema → create a new insight template
- You need a different combination of insights → create a new insight group
- The existing resource is "close but needs tweaks" → create new, don't modify the existing one
For dynamic context between calls (e.g., Class 3 Sequential Negotiation, where you inject "best quote so far" into each call), use dynamic variables passed via the scheduled events API rather than modifying the assistant. Define variable placeholders in the assistant's instructions (e.g., {{best_quote}}) and pass the values at schedule time. This keeps the assistant immutable while varying context per call.
- Assistants: Search for existing assistants. If one matches your
…(truncated)