API & Integrations
Use the Dialsheet REST API, MCP server, or AI Coworker agent to automate your sales workflow, connect external tools, and build on top of your CRM.
Pass your key in every request as a Bearer token:
Authorization: Bearer ds_your_api_keyBase URL
https://www.dialsheet.io/api/v1/leadsList leads. Supports ?search=, ?status=, ?page=, ?limit=
/api/v1/leadsCreate a new lead
/api/v1/leads/:idGet a single lead with full details
/api/v1/leads/:idUpdate lead info or status
/api/v1/leads/:idDelete a lead
# Search leads
curl "https://www.dialsheet.io/api/v1/leads?search=acme&status=new" \
-H "Authorization: Bearer ds_your_api_key"
# Create a lead
curl -X POST "https://www.dialsheet.io/api/v1/leads" \
-H "Authorization: Bearer ds_your_api_key" \
-H "Content-Type: application/json" \
-d '{"name":"Jane Smith","email":"jane@acme.com","company":"Acme","phone":"+1-555-000-1234"}'
# Update lead status
curl -X PUT "https://www.dialsheet.io/api/v1/leads/{id}" \
-H "Authorization: Bearer ds_your_api_key" \
-H "Content-Type: application/json" \
-d '{"status":"qualified"}'/api/v1/email-accountsList your configured mailboxes (needed to get email_account_id)
/api/v1/emailsSend an email via a configured mailbox
/api/v1/emailsList sent email history. Supports ?lead_id=
# Step 1 — get your mailbox IDs
curl "https://www.dialsheet.io/api/v1/email-accounts" \
-H "Authorization: Bearer ds_your_api_key"
# Step 2 — send an email
curl -X POST "https://www.dialsheet.io/api/v1/emails" \
-H "Authorization: Bearer ds_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"email_account_id": "your-mailbox-uuid",
"to_email": "prospect@company.com",
"subject": "Quick intro",
"body_text": "Hi, just reaching out...",
"lead_id": "optional-lead-uuid"
}'/api/v1/smsSend an SMS to a lead via Twilio
/api/v1/smsList SMS history. Supports ?lead_id=
curl -X POST "https://www.dialsheet.io/api/v1/sms" \
-H "Authorization: Bearer ds_your_api_key" \
-H "Content-Type: application/json" \
-d '{"lead_id":"lead-uuid","message":"Hey, following up on our call!"}'/api/v1/tasksList tasks. Supports ?lead_id=, ?completed=false
/api/v1/tasksCreate a task or follow-up reminder
/api/v1/tasks/:idUpdate or complete a task
/api/v1/tasks/:idDelete a task
/api/v1/notesList notes. Supports ?lead_id=
/api/v1/notesAdd a note with optional call outcome
# Create a follow-up task
curl -X POST "https://www.dialsheet.io/api/v1/tasks" \
-H "Authorization: Bearer ds_your_api_key" \
-H "Content-Type: application/json" \
-d '{"title":"Follow up with Jane","lead_id":"lead-uuid","due_date":"2026-03-20T10:00:00Z","priority":"high"}'
# Log a call note
curl -X POST "https://www.dialsheet.io/api/v1/notes" \
-H "Authorization: Bearer ds_your_api_key" \
-H "Content-Type: application/json" \
-d '{"lead_id":"lead-uuid","content":"Spoke for 10 min, very interested","outcome":"interested"}'/api/v1/callsCall history with transcript, ai_summary, ai_disposition, ai_next_steps, compliance_score, coaching_notes and your notes. Filters: ?lead_id=, ?date=today|yesterday|YYYY-MM-DD, ?since=, ?until=, ?tz=America/New_York, ?has_transcript=true, ?disposition=, ?include_transcript=false, ?page=, ?limit= (max 200)
/api/v1/calls/:idOne call with its full transcript and AI output
/api/v1/recapDaily recap data: the day's calls grouped by prospect with AI summaries, next steps, dispositions, notes, open tasks and deals, plus totals. ?date=, ?tz=, ?scope=team (org admins), ?include_transcripts=true
/api/v1/opportunitiesList deals. Supports ?stage=, ?lead_id=
/api/v1/opportunitiesCreate a deal/opportunity
/api/v1/opportunities/:idUpdate deal stage or value
/api/v1/tagsList all tags
/api/v1/tagsCreate a tag
/api/v1/sequencesList sequences/campaigns
/api/v1/sequences/:id/enrollEnroll a lead in a sequence
# Today's calls in your time zone, transcripts included
curl "https://www.dialsheet.io/api/v1/calls?date=today&tz=America/Chicago" \
-H "Authorization: Bearer ds_your_api_key"
# Only real conversations from last week, without transcripts in the list
curl "https://www.dialsheet.io/api/v1/calls?since=2026-09-01&until=2026-09-07&tz=America/Chicago&has_transcript=true&include_transcript=false" \
-H "Authorization: Bearer ds_your_api_key"
# Everything for a daily recap in one request
curl "https://www.dialsheet.io/api/v1/recap?date=today&tz=America/Chicago" \
-H "Authorization: Bearer ds_your_api_key"Each call carries a derived disposition (your outcome, else the AI's), is_conversation and has_transcript. Calls that were never answered have no transcript or summary.
/api/v1/webhooksList your endpoints
/api/v1/webhooksAdd an endpoint: { url, description? }. Public https URLs only, up to 10
/api/v1/webhooks/:idChange url, description or is_active
/api/v1/webhooks/:idDelete an endpoint and anything still queued for it
/api/v1/webhooks/:id/testSend a made-up call.completed marked test: true, so your tool has a request to map fields from
/api/v1/webhooks/:id/deliveriesRecent deliveries with status codes and errors, kept 30 days. ?status=pending|success|failed, ?limit=
curl -X POST "https://www.dialsheet.io/api/v1/webhooks" \
-H "Authorization: Bearer ds_your_api_key" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/hooks/dialsheet","description":"CRM sync"}'call.completed fires once per call, answered or not, when the call is finished: at least two minutes after it ends, and for answered calls once the transcript and AI summary are in (or after 20 minutes if the summary is slow). data.call is the call exactly as GET /api/v1/calls/:id returns it, with the lead's tags added:
{
"id": "5f1c...",
"type": "call.completed",
"created_at": "2026-09-22T17:04:11Z",
"test": false,
"data": {
"call": {
"id": "...", "status": "completed", "duration_seconds": 184,
"started_at": "...", "ended_at": "...", "direction": null,
"from_number": "+15555550100", "recording_url": "https://api.twilio.com/.../RE....mp3",
"disposition": "interested", "is_conversation": true,
"ai_summary": "...", "ai_disposition": "interested", "ai_next_steps": "...",
"has_transcript": true, "transcript": "Rep: ...",
"notes": [{ "outcome": "interested", "content": "Demo Thursday", "created_at": "..." }],
"leads": {
"id": "...", "name": "Jane Example", "company": "Example Roofing",
"phone": "+15555550123", "email": "jane@example.com", "status": "interested",
"tags": [{ "id": "...", "name": "Hot lead", "color": "#16a34a" }]
}
}
}
}Every request carries X-DialSheet-Signature: t=<unix seconds>,v1=<hex>, where v1 is HMAC-SHA256 of t + "." + raw body keyed with the endpoint's signing secret (whsec_…). Tools that cannot check it, like GoHighLevel's inbound webhook, can ignore it; keep the URL private instead.
import crypto from 'crypto';
function verify(secret: string, rawBody: string, header: string) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
return fresh && expected.length === (parts.v1 || '').length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}Answer with any 2xx within 10 seconds. Failures retry after 1, 5, 30, 120 and 720 minutes; an endpoint that fails every retry on 10 calls in a row is switched off. Delivery is at least once and not in order; id stays the same across retries, so dedupe on it. A webhook sends the calls of the person who added it, the same as their API key. Pro plan.
All responses are JSON. Errors always include an error field.
# Success
{ "lead": { "id": "...", "name": "Jane Smith", ... } }
# Error
{ "error": "Lead not found" } // HTTP 404
{ "error": "Unauthorized" } // HTTP 401 — check your API keyList endpoints return a wrapper object, e.g. { "leads": [...], "total": 142 }