dialsheet.io

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.

Pro feature
Authentication
All API requests require your personal API key. Generate one at Settings → API Keys.

Pass your key in every request as a Bearer token:

Authorization: Bearer ds_your_api_key

Base URL

https://www.dialsheet.io
Leads
GET
/api/v1/leads

List leads. Supports ?search=, ?status=, ?page=, ?limit=

POST
/api/v1/leads

Create a new lead

GET
/api/v1/leads/:id

Get a single lead with full details

PUT
/api/v1/leads/:id

Update lead info or status

DELETE
/api/v1/leads/:id

Delete 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"}'
Emails
GET
/api/v1/email-accounts

List your configured mailboxes (needed to get email_account_id)

POST
/api/v1/emails

Send an email via a configured mailbox

GET
/api/v1/emails

List 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"
  }'
SMS
POST
/api/v1/sms

Send an SMS to a lead via Twilio

GET
/api/v1/sms

List 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!"}'
Tasks & Notes
GET
/api/v1/tasks

List tasks. Supports ?lead_id=, ?completed=false

POST
/api/v1/tasks

Create a task or follow-up reminder

PUT
/api/v1/tasks/:id

Update or complete a task

DELETE
/api/v1/tasks/:id

Delete a task

GET
/api/v1/notes

List notes. Supports ?lead_id=

POST
/api/v1/notes

Add 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"}'
Calls   Opportunities   Tags
GET
/api/v1/calls

Call 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)

GET
/api/v1/calls/:id

One call with its full transcript and AI output

GET
/api/v1/recap

Daily 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

GET
/api/v1/opportunities

List deals. Supports ?stage=, ?lead_id=

POST
/api/v1/opportunities

Create a deal/opportunity

PUT
/api/v1/opportunities/:id

Update deal stage or value

GET
/api/v1/tags

List all tags

POST
/api/v1/tags

Create a tag

GET
/api/v1/sequences

List sequences/campaigns

POST
/api/v1/sequences/:id/enroll

Enroll 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.

Webhooks
DialSheet POSTs each finished call to a URL you own, so nothing has to poll. Point it at a GoHighLevel inbound webhook, Zapier, Make, n8n or your own server. Add endpoints under Settings, Webhooks, or with the routes below.
GET
/api/v1/webhooks

List your endpoints

POST
/api/v1/webhooks

Add an endpoint: { url, description? }. Public https URLs only, up to 10

PUT
/api/v1/webhooks/:id

Change url, description or is_active

DELETE
/api/v1/webhooks/:id

Delete an endpoint and anything still queued for it

POST
/api/v1/webhooks/:id/test

Send a made-up call.completed marked test: true, so your tool has a request to map fields from

GET
/api/v1/webhooks/:id/deliveries

Recent 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.

Response format

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 key

List endpoints return a wrapper object, e.g. { "leads": [...], "total": 142 }

Questions? Reach out to our support team.Contact support