Developers

Build calling, messaging and voice AI into your product

Three ways in: drop ready-made UI into your app, send outreach over a REST API, or build on the same voice intelligence that powers Drop Cowboy®.

REST base URL: https://api-v2.dropcowboy.com

See it in code

Real requests against the live API. Set DC_KEY and DC_SECRET to your API key pair.

Building Blocks: mint a token on your server
// Your server. Browser code never sees KEY/SECRET. The key needs numbers:write.
app.post('/dropcowboy/token', async function (req, res) {
  const r = await fetch('https://api-v2.dropcowboy.com/phone/public/embed/token', {
    method: 'POST',
    headers: {
      'x-key': process.env.DC_KEY,
      'x-secret': process.env.DC_SECRET,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ site_id: process.env.DC_SITE_ID, scope: ['dialer:webrtc', 'contacts'], ttl_seconds: 900 })
  });
  res.status(r.status).json(await r.json());
});
Building Blocks: drop the dock into your app
<script src="https://webforms.dropcowboy.com/latest/dropcowboy-dock.min.js"></script>
<script>
(async function () {
  const minted = await fetch('/dropcowboy/token', { method: 'POST' }).then(function (r) { return r.json(); });
  await DropCowboy.dock.init({
    token: minted.token,
    mode: 'floating',
    panes: ['dialer', 'inbox', 'contacts']
  });
})();
</script>
Send a ringless voicemail
curl -X POST https://api-v2.dropcowboy.com/rvm \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+13125550142",
    "phone_line_id": "e2b6f9a3-5c1d-4e8b-a4f7-9c3e1b5d7a28",
    "media_id": "1b7e3c9a-4d2f-4a8b-9e6c-7f2a1d5b3c80",
    "foreign_id": "order-1042"
  }'
Send a text
curl -X POST https://api-v2.dropcowboy.com/sms \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+13125550142",
    "phone_line_id": "e2b6f9a3-5c1d-4e8b-a4f7-9c3e1b5d7a28",
    "body": "Your order is ready for pickup. Reply STOP to opt out.",
    "foreign_id": "order-1042"
  }'
Send an email
curl -X POST https://api-v2.dropcowboy.com/email/public/email \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "to": [{ "address": "jordan.rivera@example.com", "name": "Jordan Rivera" }],
    "mailbox_id": "c5f1a8d3-6e2b-4c9f-b1a7-8d4e2c6f9b35",
    "subject": "Your order is ready",
    "html": "<p>Hi Jordan, your order is ready for pickup.</p>"
  }'
Detection: connect and stream a call
// npm install ws. The Detection API key comes from support; keep it server-side.
const WebSocket = require('ws');

const ws = new WebSocket('wss://detect.dropcowboy.com/carrier/ws', {
  headers: { Authorization: 'Bearer ' + process.env.DETECTION_API_KEY }
});

ws.on('open', () => {
  ws.send(JSON.stringify({
    type: 'welcome',
    payload: {
      call_id: '4e8c2a6d-1f9b-4d3e-a5c7-2b6f8d4a9e31',
      audio_encoding: 'pcm16',
      sample_rate_hz: 8000,
      strategy: 'standard'
    }
  }));
});

ws.on('message', (data, isBinary) => {
  if (isBinary) return;
  const msg = JSON.parse(data.toString());
  if (msg.event === 'ready') {
    // Start sending the call audio as binary frames, in real time.
  }
  if (msg.event === 'detection' && msg.payload.is_final) {
    console.log('answered by', msg.payload.type);
  }
  if (msg.event === 'beep') {
    // The beep ended: start your message now.
  }
});

// When the call ends:
// ws.send(JSON.stringify({ command: 'stop' }));
Text-to-speech
curl https://api-v2.dropcowboy.com/voice/public/tts/synthesize \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "voice_id": "7d2a9e4b-1c6f-4b3a-8e5d-2f9c7a1b4e63",
    "text": "Thanks for calling Example Dental. How can I help?"
  }'
Build an AI receptionist
# 1. A knowledge base the agent answers from (then add documents to it)
curl -X POST https://api-v2.dropcowboy.com/document/public/knowledge-bases \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Customer FAQ", "description": "Hours, pricing and service area for callers.", "ai_audience": "public" }'

# 2. An agent from an inbound template. Attach the knowledge base in
#    think.knowledge (see /developers/api/agents), then publish.
curl -X POST https://api-v2.dropcowboy.com/agents/public/agents/from-template \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "template_id": "inbound-appointment-setting", "name": "Front desk", "active": true }'

curl -X POST https://api-v2.dropcowboy.com/agents/public/agents/$AGENT_ID/publish \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"

# 3. A phone line whose rules send calls to the agent (line.json:
#    see /developers/api/agents/ai-receptionist), then assign your number.
curl -X POST https://api-v2.dropcowboy.com/phone/public/lines \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
  -H "Content-Type: application/json" \
  -d @line.json

curl -X POST https://api-v2.dropcowboy.com/phone/public/lines/$LINE_ID/assign \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "number": "+13125550142" }'

Your first request in three steps

  1. Create an API key

    In the dashboard, open Developers and create a key pair with the scopes you need. Send it as the x-key and x-secret headers.

  2. Subscribe to results

    A send answers 202 when it is accepted. Subscribe to the status webhook for each channel so you learn the result of each send.

  3. Send to yourself

    Add your own numbers as test numbers on the Dialing rules page. They skip the contact frequency limit while you build.

Developer questions

How do I authenticate?
Send your API key pair as the x-key and x-secret headers on every request to https://api-v2.dropcowboy.com. Server-to-server integrations can instead use OAuth 2.0 client credentials: exchange a client id and secret at https://login.dropcowboy.com/oauth/token for a bearer token.
Does a 202 mean my message was delivered?
No. A 202 means the send was accepted. Compliance checks run after that, and the result arrives on the status webhook for the channel, with a reason_code that explains any failure.
What happens outside calling hours?
Voice sends (ringless voicemail, voice broadcast, AI calls) are held and retried for up to 3 days, then fail with tcpa_expired. Texts sent outside the contact's window (federal and state-specific calling hours in their time zone) fail with reason_code 4011 and are not retried, so resend them inside the window. Always consult with your legal counsel to confirm compliance procedures for your specific use case.
Why did a send fail with 4013?
The number reached your team's contact frequency limit, by default 3 attempts in 3 days. Account owners can change it on the Dialing rules page, and GET /register/public/account returns the current limit. Test numbers are exempt.
Which HTTP client should I use?
Any of them. Every feature is a plain HTTPS request, and the docs include curl, JavaScript and Python samples.
How do opt-outs work?
When a contact replies STOP to one of your numbers, Drop Cowboy records the opt-out and fires the contact.msg.opt_out webhook, so you can mirror it in your own system. Always consult with your legal counsel to confirm compliance procedures for your specific use case.
How do I get a Detection API key?
Detection uses its own key, separate from your REST API keys. Create one on the Detection page in the dashboard, or with POST /register/public/detection-keys. Keep it on your server.

Building something bigger?

Talk to us about volume, dedicated numbers, or embedding Drop Cowboy in your platform.