Building Blocks

Ready-made calling, texting, inbox, and campaign UI you drop into your product, plus voice APIs your server calls. Widgets load with one script tag and a short-lived site token.

How widgets work

Every block is either a drop-in widget your page loads with one script tag, or an API your server calls. Widgets never see your API key.

How widgets authenticate

  1. Your server trades its API key for a short-lived site token with POST https://api-v2.dropcowboy.com/phone/public/embed/token. The token lasts one hour at most and carries only the scopes you ask for.
  2. Your page loads the widget script and calls init({ token }). Mint a new token when it expires.
  3. The token goes in init(), never in a URL, and the API key never reaches the browser.

See Embed site tokens for scopes and the full request.

Rules for integrators and AI agents

  • Do not rebuild WebRTC calling or the inbox. Use the Dock, Dialer, and Shared Inbox.
  • Do not configure SIP, STUN, or TURN servers in your page. The calling widgets get that from the site token.
  • Detection runs on your server over a WebSocket with a Detection API key. The browser is never part of it.
  • Headless work (sending, contacts, campaigns) goes to the REST API or MCP.
  • To add your own panel inside the Drop Cowboy® dashboard rather than embed Drop Cowboy in your app, use a Canvas widget: your server answers a signed request with Canvas JSON.

Every block

Block Type Auth What it does
The Dock (one widget) Widget Site token (dialer:webrtc contacts) One widget for a CRM: click a contact, dial, text, and open inbox.
Web Chat Script tag None, origin checked Visitor chat on your site, with handoff to SMS or a live call.
Messenger (SMS/MMS/RCS) Widget Site token (dialer:webrtc) Two-way SMS from your app, sent from your business number.
Shared Inbox Widget Site token (dialer:webrtc) One inbox for texts, chat, voicemail, and calls.
Dialer / Softphone Widget Site token (dialer:webrtc) Softphone in the browser. Click a contact, place the call.
AI Receptionist Widget Site token (dialer:webrtc) Let visitors talk to your AI agent from your app.
Phone Hub (Inbound) Widget Site token (phone:hub) Pick a number, set hours, and route inbound calls.
Detection (AMD / Beep / Screening) API Detection API key Person, machine, or beep, on our dialer or your carrier.
Text-to-Speech API API key Turn text into a recording with a stock or cloned voice.
Voice Clone (Mimic AI) API API key Clone a voice from a recording you have permission to use.
Speech-to-Text (ASR) API API key Turn a recording into a transcript.
Recording Studio Widget Site token (media) Record, upload, or generate a greeting.
Web Forms Script tag None, origin checked Lead-capture forms with TCPA consent built in.
Consent Capture Widget Site token (dialer:webrtc) Capture a yes before you call or text, tied to the number.
Click-to-Call Widget Site token (dialer:webrtc) A button that calls you, or requests a callback.
Click-to-Text Widget Site token (dialer:webrtc) A button that starts an SMS to your business number.
Contacts & Pipeline Widget Site token (contacts) Open a contact card, timeline, and pipeline stage.
Campaign Builders Widget Site token (campaigns) Show campaign status and start or pause from your app.
Website Analytics & Events Script tag None, origin checked Page views, sessions, and custom events from your site.
Headless API & MCP API API key REST and MCP for servers and LLM agents. No widget.

The two-step pattern

Mint a token on your server, then load a widget with it. Every widget works the same way.

Mint a site token (your server)
// Your server. Browser code never sees KEY/SECRET.
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 })
  });
  const body = await r.json();
  if (!r.ok) return res.status(r.status).json(body);
  // The API wraps results in data. Hand the browser just the token.
  res.json({ token: body.data.token, expires_at: body.data.expires_at });
});
Load the Dock
<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']
  });
  DropCowboy.dock.setTheme({ theme: 'LIGHT', primaryColor: '#009efb' });

  DropCowboy.dock.addPaneChangeListener(function (event) {
    console.log('dock pane', event.pane);
  });

  document.getElementById('contacts').addEventListener('click', function (e) {
    var row = e.target.closest('[data-contact-id]');
    if (!row) return;
    DropCowboy.dock.dial({
      contact: {
        id: row.getAttribute('data-contact-id'),
        name: row.getAttribute('data-name'),
        phone: row.getAttribute('data-phone')
      }
    });
  });
})();
</script>
Send a text from your server
curl -X POST https://api-v2.dropcowboy.com/sms \
  -H "x-key: $KEY" -H "x-secret: $SECRET" \
  -H "Content-Type: application/json" \
  -d '{"to":"+15125550148","phone_line_id":"e2b6f9a3-5c1d-4e8b-a4f7-9c3e1b5d7a28","body":"Hi from Drop Cowboy"}'