DEV Community

voipbin
voipbin

Posted on

Add a 'Call Me Back' Button to Any Website — Backed by an AI Agent

There is a feature that almost every product manager has requested at least once: a "Call Me Back" button.

The user fills in their phone number, hits the button, and within seconds — an agent calls them back.

The problem? Traditionally this meant integrating with a call center, managing agents, paying per-seat licensing, and hoping someone picks up at 2am.

With an AI agent backed by VoIPBin, you can build this entire flow yourself — triggered from a simple API call, available 24/7, no human required.

This post walks through the full implementation.


What We Are Building

User clicks "Call Me Back" on your website
        ↓
Your backend calls VoIPBin API → outbound call placed
        ↓
User picks up → AI agent speaks greeting
        ↓
STT captures user voice → your webhook receives transcript
        ↓
You run logic (answer questions, qualify lead, collect info)
        ↓
TTS responds → conversation continues until resolved
Enter fullscreen mode Exit fullscreen mode

Your server handles only text. VoIPBin handles the call, audio codec negotiation, STT, TTS, and everything telephony-related.


Step 1: Get Your API Key

No credit card required to start. Sign up with a single request:

curl -s -X POST https://api.voipbin.net/v1.0/auth/signup \
  -H "Content-Type: application/json" \
  -d '{
    "username": "yourname",
    "password": "yourpassword",
    "email": "you@example.com"
  }'
Enter fullscreen mode Exit fullscreen mode

The response includes accesskey.token — that is your API key.


Step 2: The Frontend Button

A minimal "Call Me Back" form in plain HTML:

<form id="callback-form">
  <label for="phone">Your phone number</label>
  <input type="tel" id="phone" name="phone"
         placeholder="+1 415 555 0100" required />
  <button type="submit">Call Me Back</button>
</form>

<script>
document.getElementById("callback-form").addEventListener("submit", async (e) => {
  e.preventDefault();
  const phone = document.getElementById("phone").value;

  const res = await fetch("/api/callback", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ phone })
  });

  const data = await res.json();
  if (data.ok) {
    alert("Calling you now!");
  }
});
</script>
Enter fullscreen mode Exit fullscreen mode

Step 3: Backend — Place the Outbound Call

Your /api/callback endpoint receives the user's phone number and triggers an outbound call via VoIPBin.

Here is a Node.js/Express example:

const express = require("express");
const app = express();
app.use(express.json());

const VOIPBIN_TOKEN = process.env.VOIPBIN_TOKEN;
const YOUR_CALLER_ID = "+15550001234"; // your VoIPBin number
const WEBHOOK_URL = "https://yourapp.com/api/voice-webhook";

app.post("/api/callback", async (req, res) => {
  const { phone } = req.body;

  const response = await fetch("https://api.voipbin.net/v1.0/calls", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${VOIPBIN_TOKEN}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      source: { type: "tel", target: YOUR_CALLER_ID },
      destinations: [{ type: "tel", target: phone }],
      flow_id: null,
      webhook: { url: WEBHOOK_URL }
    })
  });

  const call = await response.json();
  console.log("Call placed:", call.id);
  res.json({ ok: true, call_id: call.id });
});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

Once the user picks up, VoIPBin fires events to your webhook.


Step 4: The AI Agent — Webhook Handler

When the call connects, VoIPBin sends a call.started event. You respond with instructions: speak a greeting, then listen for input.

app.post("/api/voice-webhook", async (req, res) => {
  const event = req.body;

  if (event.type === "call.started") {
    return res.json({
      actions: [
        {
          type: "talk",
          text: "Hi! Thanks for requesting a callback from Acme. What can I help you with today?"
        },
        {
          type: "listen",
          timeout: 8,
          max_duration: 15
        }
      ]
    });
  }

  if (event.type === "call.transcription") {
    const userSaid = event.transcript;
    const aiReply = await getAIReply(userSaid);

    return res.json({
      actions: [
        {
          type: "talk",
          text: aiReply
        },
        {
          type: "listen",
          timeout: 8,
          max_duration: 20
        }
      ]
    });
  }

  if (event.type === "call.ended") {
    console.log("Callback call completed:", event.call_id);
    return res.json({ ok: true });
  }

  res.json({});
});
Enter fullscreen mode Exit fullscreen mode

Step 5: Connect an LLM

The getAIReply function is where your product logic lives. A minimal example using OpenAI:

const { OpenAI } = require("openai");
const openai = new OpenAI();

async function getAIReply(userMessage) {
  const completion = await openai.chat.completions.create({
    model: "gpt-4o-mini",
    messages: [
      {
        role: "system",
        content: "You are a helpful support agent for Acme Corp. Answer questions about our product concisely. If the user wants to speak to a human, say: I will transfer you now. Keep responses under 2 sentences for phone clarity."
      },
      { role: "user", content: userMessage }
    ]
  });

  return completion.choices[0].message.content;
}
Enter fullscreen mode Exit fullscreen mode

Swap OpenAI for Anthropic Claude, Google Gemini, or any LLM — the interface stays the same.


What You Just Built

With roughly 80 lines of code, you have:

  • A working "Call Me Back" button any website can embed
  • Outbound calls triggered by your backend
  • AI agent that greets and converses with callers
  • STT to LLM to TTS pipeline, fully managed by VoIPBin
  • No telephony infrastructure to operate

Your team never picks up the phone. The AI handles the first touch, qualifies the question, or resolves it entirely.


Extensions Worth Building

Escalate to a human when needed:

if (aiReply.includes("transfer you now")) {
  return res.json({
    actions: [
      { type: "talk", text: "Connecting you to our team." },
      { type: "transfer", destination: { type: "tel", target: "+15559998888" } }
    ]
  });
}
Enter fullscreen mode Exit fullscreen mode

Log every callback to a CRM:

if (event.type === "call.ended") {
  await crm.createTicket({
    phone: event.caller,
    summary: conversationSummary,
    resolved: !escalated
  });
}
Enter fullscreen mode Exit fullscreen mode

Respect business hours — schedule the call for later:

if (!isBusinessHours()) {
  const scheduledAt = nextBusinessHourTimestamp();
  body.scheduled_at = scheduledAt;
}
Enter fullscreen mode Exit fullscreen mode

Try It

  • Docs and API reference: https://voipbin.net
  • Golang SDK: go get github.com/voipbin/voipbin-go
  • MCP server (use from Claude Code or Cursor): uvx voipbin-mcp

Signup takes one API call. No OTP, no waiting, no approval queue.

If you build something interesting with this, drop it in the comments.

Top comments (0)