dialpad
Skill2 starsChanged 52 days agoMITView on GitHub
Send SMS and make voice calls via Dialpad API using task-focused wrappers backed by an OpenAPI-generated CLI.
- Reads credentials
The file
We split this skill into the rules it gives an agent
8 rules. About 0 are common, 2 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 15
Use this skill to:
- Very specific: line 75
When DIALPAD_LOG_URL is configured, SMS thread/inbox reads and call-list reads use the authenticated theshop interaction log by default.
- Very specific: line 104
Escaping: Use single quotes for inline --message values containing $ to prevent shell expansion (e.g., 'Price is $10').
- Very specific: line 105
Safer message input: Prefer --message-file or --message-stdin for pricing text, multi-line copy, or anything shell-sensitive.
- Very specific: line 106
Supported agent interface: use bin/*.py wrappers for normal work.
- Very specific: line 113
default fallback order: DIALPAD_DEFAULT_FROM_NUMBER, then DIALPAD_DEFAULT_PROFILE
- Very specific: line 124
Receipt phrasing: When confirming an SMS send to an operator, always include To: <number> in the receipt text so the downstream guard can …
- Distinctive: line 146
Use these only for manual operator workflows, storage inspection, and maintenance:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Dialpad Skill
Send SMS and make voice calls via the Dialpad API.
When to Use
Native tools: submit_draft (registered by this skill's dialpad-draft-callback plugin). Owned entrypoints: list_sms_thread.py, list_sms_inbox.py, list_call_history.py, lookup_contact.py, poll_voicemails.py.
Use this skill to:
- Send SMS messages (individual or batch)
- Make voice calls (with TTS or custom voices)
- Manage contacts and organization settings
- Inspect SMS and call history through operator tooling when needed
Available Phone Numbers
| Number | Purpose | Format |
| (415) 555-0140 | Sales Team | Default for sales context |
| (415) 555-0100 | Work/Personal | Default for work context |
| (415) 555-0141 | Support SMS Only | SMS only (no voice) |
Quick Start
Send SMS (explicit sender recommended):
bin/send_sms.py --to "+14155551234" --from "+14155550140" --message 'Hello from OpenClaw!'Send an operator-approved SMS and close a shown approval draft (agent direct path):
bin/send_sms.py --to "+14155551234" --from "+14155550140" --message 'Exact approved text' --resolve-draft-id smsdraft_abc123 --approval-actor-id "telegram-user-123" --approval-actor-username "operator" --jsonCreate/approve an SMS draft (human approval path):
bin/create_sms_draft.py --thread-key "manual:thread" --to "+14155551234" --from "+14155550140" --message 'Exact draft text' --json
bin/approve_sms_draft.py smsdraft_abc123 --actor-id "telegram-user-123" --actor-username "operator" --approval-token "$DIALPAD_SMS_APPROVAL_TOKEN" --jsonGroup Intro (mirrored fallback):
bin/send_group_intro.py --prospect "+14155550111" --reference "+14155559999" --confirm-share --from "+14155550100"Make Call (TTS):
bin/make_call.py --to "+14155551234" --text "This is a call from the agent."List Recent Calls:
bin/list_calls.py --today --limit 20
bin/list_calls.py --hours 6 --missed --jsonGet Call Transcript:
bin/get_call_transcript.py --call-id "call_123" --json
bin/get_call_transcript.py --last --with "+14155551234" --jsonCheck SMS Thread History:
bin/list_sms_thread.py --phone "+14155551234" --json
bin/list_sms_inbox.py --limit 20 --jsonWhen DIALPAD_LOG_URL is configured, SMS thread/inbox reads and call-list
reads use the authenticated theshop interaction log by default. Use
bin/list_calls.py --live only for an explicit live Dialpad query and
--local for the legacy local calls database. After a successful
bin/send_sms.py, the exact outbound observation is recorded through the
shared log or queued in the record-only DIALPAD_LOG_OUTBOX; replaying that
outbox never sends SMS or places calls. It drains itself on the next send or
read, bounded so a dead log never delays the command that triggered it; see
references/sms-storage.md for the drain knobs, the run record, and the
breach alert.
Sync Direct Dialpad SMS Sends:
bin/sync_sms_export.py --start-date 2026-05-13 --end-date 2026-05-13 --jsonCreate Contact:
bin/create_contact.py --first-name "Jane" --last-name "Doe" --phone "+14155550123" --email "jane@example.com"Update Contact:
bin/update_contact.py --id "contact_123" --phone "+14155550123" --job-title "VP"Key Rules
- Destination policy: Outbound SMS and calls support NANP (
+1) destinations only, including all NANP territories. Non-NANP international destinations are rejected before any Dialpad API request. Always use E.164 format (e.g.,+14155551234); SMS country inference normalizes ten-digit NANP input to explicit+1E.164. The generatedmessage schedules.send_nowcommand is disabled because stored recipients cannot be validated locally; schedule updates must repeat phone recipients through--dataas a JSON array; meeting updates must setcall_outthrough--dataas a JSON boolean; and generated meeting create/update commands cannot enable call-out. - Escaping: Use single quotes for inline
--messagevalues containing$to prevent shell expansion (e.g.,'Price is $10'). - Safer message input: Prefer
--message-fileor--message-stdinfor pricing text, multi-line copy, or anything shell-sensitive. - Supported agent interface: use
bin/*.pywrappers for normal work. They are the stable command contract for agents. - Operator-only surfaces:
generated/dialpadandscripts/*are for manual troubleshooting, storage inspection, or operational maintenance, not normal agent task execution. - Auth canonical source:
DIALPAD_API_KEYis canonical.DIALPAD_TOKENis only needed for manual generated CLI troubleshooting (bridge command in Setup below). - SMS sender safety:
--fromand--profile work|salesare supported. Prefer explicit--fromfor deterministic routing.--profilemaps to configured env vars:- work:
DIALPAD_PROFILE_WORK_FROM - sales:
DIALPAD_PROFILE_SALES_FROM
- work:
- default fallback order:
DIALPAD_DEFAULT_FROM_NUMBER, thenDIALPAD_DEFAULT_PROFILE --allow-profile-mismatchpermits explicit/profile mismatches when intentional--dry-runprints sender resolution and the exact message/request preview without an API call
- Group intro:
bin/send_group_intro.pymirrors intro messages as two one-to-one SMS sends (mirrored_fallback) because true group threads are unsupported via this wrapper. - Call history:
bin/list_calls.pyis the supported call-history command for agents (supporting--today,--hours,--missed, and--localfor offline store queries).bin/list_call_history.pyprovides dedicated read-only local store queries with--phone,--direction,--min-duration, and--transcript-onlyfilters. Use--jsonwhen downstream automation needs a deterministic response envelope. - Call transcripts:
bin/get_call_transcript.pyis the supported transcript retrieval command for agents. It supports--localto retrieve transcripts deterministically from the local SQLite store without hitting the live Dialpad API. When hitting the live API, it uses Dialpad's plural transcript endpoints (GET /api/v2/transcripts/{call_id}and optional review URLGET /api/v2/transcripts/{call_id}/url); singular/api/v2/transcript/{id}is not the supported endpoint. It is transcript-only; AI recap, CRM enrichment, and follow-up drafting are intentionally separate work. - Call & SMS local stores: Incoming webhooks persist events in local append-only SQLite databases (
DIALPAD_SMS_DBdefaulting to/home/art/niemand/logs/sms.db, andDIALPAD_CALLS_DBdefaulting to/home/art/niemand/logs/calls.db). Before saying a contact was not messaged or called, inspect local history first. For SMS, runbin/list_sms_thread.py --phone PHONE --jsonand checkhas_outbound/outbound_count. For calls, runbin/list_call_history.py --phone PHONE --json. - SMS export sync:
bin/sync_sms_export.pyimports Dialpad Stats text export metadata into local SQLite for direct Dialpad UI sends and other out-of-band messages. It skips existing message IDs to preserve webhook-captured text. - Create/Update Contact Behavior:
bin/create_contact.pyupserts shared/local contacts by phone/email match (or forces create with--allow-duplicate).bin/update_contact.pyupdates by--idwith partial fields. - Current-turn verification: "Already sent" and "Already updated" are only valid after a fresh current-turn tool result, not from stale session memory. If the current turn has not verified the action yet, say that plainly and run the tool now.
- SMS receipt ledger: Successful sends through
bin/send_sms.py, both legs ofbin/send_group_intro.py, and approval-lane sends append authoritative JSONL receipt evidence toDIALPAD_SMS_RECEIPT_LEDGER, defaulting to/data/.openclaw/state/dialpad/sms-receipts.jsonl. Failed sends and dry runs do not write receipts. - Receipt phrasing: When confirming an SMS send to an operator, always include
To: <number>in the receipt text so the downstream guard can bind the claim to the ledger recipient. - Delivery-status webhooks:
bin/create_sms_webhook.py createprovisions the SMS subscription withstatus: true. Authenticated sparse delivery events update only the matchingsms.dbrow by provider message ID and never enter inbound dedupe, OpenClaw hooks, Telegram, or approval-draft fan-out. Receipt events require a parseable providerevent_timestamp; an empty oracceptedresult is required alongsidedelivered, while unknown, stale, and contradictory states fail closed. - Identity guardrail: For first-contact work, soft signals like first name, area code, industry, or job title are not enough to merge or update a contact. Keep uncertain identity
draft-onlyfor autonomous sends and contact mutation — let the CRM layer prove the match before auto-sending or mutating anything. However, explicit operator approval (rule 20) lifts the draft-only send restriction: the whole point of the approval path is that the human makes the identity judgment call. Do not refuse to send a draft that an operator has explicitly approved in the current turn. - Inbound context guardrail: Webhook
inboundContextbriefs explain identity evidence, recent SMS/call continuity, source status, and draft basis. Low-confidence Sales SMS and missed calls may get generic approval drafts, but not personalized claims. Known contacts only get context-aware, CRM-aware, meeting-aware, or availability-aware approval drafts when identity confidence is high and relevant continuity is no older than 14 days; stale or degraded context stays brief-only. Calendar lookup is only for obvious meeting logistics and demo-prospect availability requests, not every inbound SMS. If availability cannot be verified, do not turn the CRM generic fallback into a scheduling reply. Demo-context missed calls may include operator-only prior-comms provenance from SMS/Gmail counts; raw comms bodies must not be copied into customer-facing draft text. If a model is used for final wording, it must receive compact tool-call facts plus the deterministic fallback and fail closed to that fallback on unsafe or unsupported output. - Inbound automation guardrail: Dialpad inbound hooks may create SMS approval drafts, but they must not send customer SMS directly. Use
bin/approve_sms_draft.pyonly with a real human actor id and an operator-onlyDIALPAD_SMS_APPROVAL_TOKEN; agent/bot actors are rejected by the trusted approval ledger. - Operator-approved agent sends: Agents may send SMS with
bin/send_sms.pyafter explicit current-turn operator approval. When resolving a shown approval draft, pass--resolve-draft-idplus--approval-actor-id/--approval-actor-usernameso the draft closes as an auditedagent_direct_send; that actor context is agent-asserted unless it came through a trusted Telegram/shell approval surface. Risky drafts still require the existing two-step approval state before--confirm-riskcan send. - Opt-out guardrail: Explicit opt-out language is a hard stop. Do not create override drafts or send follow-ups on those threads unless a human operator handles the conversation outside automation.
- Operator notification ownership: One inbound SMS or missed call should create one operator-visible Telegram message per target by default. When the local Dialpad Telegram approval card and OpenClaw hook route point at the same Telegram destination, the local card owns visibility and the hook is context-only with
deliver=false. UseDIALPAD_ALLOW_DUPLICATE_OPERATOR_DELIVERY=1only for intentional same-target fanout. - Generated CLI command structure & safe discovery: The underlying generated CLI uses
<resource> <resource>.<method>naming (e.g.dialpad sms sms.send,dialpad users users.get,dialpad call call.create_call). Avoid probing guessed subcommands such asusers list(which does not exist in this generated CLI). When inspecting commands, usegenerated/dialpad <resource> --helpor rely onbin/*.pywrappers. - Send SMS managed environment & direct API fallback:
bin/send_sms.pyexecutes generated Dialpad CLI calls through a managed environment built into the skill copy: the wrapper's own interpreter runsgenerated/dialpadwithvendor/(constructed from the pinned, hash-verifiedrequirements.txtbyscripts/build_vendor.py; provenance and delivery indocs/reference/vendor-build.mdanddocs/reference/runtime-copies.md) onPYTHONPATH, so click always imports from the repo tree — never from an ambient system python, aPATHlookup, or auvbinary that non-interactive runtimes (systemd, agent exec, cron) do not reliably carry (the #89uv-discovery fix regressed in #155 exactly this way). If the generated CLI or its Python runtime dependencies are missing anyway,bin/send_sms.pyfalls back to direct Dialpad API execution as a safety net, and a draft claimed for such a local failure returns to a retryablepending/risk_pendingstate instead of being terminallyfailed, so approved outbound SMS messages are neither lost nor stuck on environment gaps.
Reference Documentation
references/api-reference.md— Wrapper behavior, operator CLI reference, Webhooksreferences/openclaw-integration.md— End-to-end setup guide for wiring this repo's webhook server to OpenClaw with human approval defaultsreferences/sms-storage.md— SQLite commands, FTS5 search, legacy storagereferences/voice-options.md— List of available TTS voices (Budget & Premium)references/architecture.md— System architecture, wrappers, and CLI generationTHEORY.MD— Design rationale: shell-corruption invariant, 401 classification, inbound-policy-once model
Operational Tools
Use these only for manual operator workflows, storage inspection, and maintenance:
python3 scripts/sms_sqlite.py list
python3 scripts/webhook_server.pySetup
Required environment variable:
export DIALPAD_API_KEY="your_key"Operator auth bridge for manual generated CLI troubleshooting:
export DIALPAD_TOKEN="${DIALPAD_TOKEN:-$DIALPAD_API_KEY}"Optional:
export ELEVENLABS_API_KEY="your_key"
export DIALPAD_USER_MAP='{"+14155550100": "5765607478525952"}'
export DIALPAD_PROFILE_WORK_FROM="+14155550100"
export DIALPAD_PROFILE_SALES_FROM="+14155550140"
export DIALPAD_DEFAULT_PROFILE="work"
export DIALPAD_DEFAULT_FROM_NUMBER="+14155550140"
export DIALPAD_SMS_RECEIPT_LEDGER="/data/.openclaw/state/dialpad/sms-receipts.jsonl"
export DIALPAD_DRAFT_CALLBACK_URL="http://host.docker.internal:8888/internal/draft-callback"For merged agent-draft flow, keep DIALPAD_DRAFT_CALLBACK_URL aligned with the
OpenClaw dialpad-draft-callback plugin callbackUrl config. The default
host.docker.internal URL is for gateway-container to host-webhook delivery.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

