Call Bullet

Build a click-to-call button in an AI-built app

A click-to-call button lets a customer ask to be called, then Call Bullet rings your staff phone first and connects the customer from your business line. Your app sends one POST /calls/click-to-call request; calling hours, TPS, do-not-call and spend caps are checked on every call before anything rings.

Last updated · Call Bullet

What is click-to-call?

Click-to-call turns a “call me back” request into a live phone call in seconds, with a person on your side of the line.

There are two kinds. The simplest is a tel: link, which opens the visitor's own dialler to ring you. The second, covered here, is a callback: the visitor enters their number, your staff phone rings, and when staff answer Call Bullet dials the customer and joins the two. The customer sees your business number, and the call is logged in your outbound history.

tel: linkCallback via API
Who dialsThe visitorCall Bullet, after staff answer
Works on desktopOnly with a calling appYes
Caller IDVisitor's numberYour business line
Logged in Call BulletIf the number is trackedAlways, as an outbound call
SetupOne line of HTMLOne API call plus a form

What do I need first?

You need an active outbound phone line and a key with the click-to-call permission.

  1. In Call Bullet, add a business phone line under Outbound → Phone numbers and set the staff phone it rings.
  2. Create an API key with workspaces:read, phone_lines:read and calls:place. calls:place is switched on by itself.
  3. Find the line's ID with GET /workspaces/{id}/phone-lines.
  4. Add a callback form to your app that collects the customer's number and records their request.

How do I place the call?

Send the request from a server function. consent_ref is your record of the customer's request, such as the form submission ID.

TypeScript · request a callback
import { cb } from "./call-bullet.server";

export async function requestCallback(opts: { workspaceId: string; lineId: string; to: string; formId: string }) {
  try {
    const { data } = await cb<{ data: { id: string; status: string; call_id: string | null } }>(
      "/calls/click-to-call",
      {
        method: "POST",
        headers: { "Idempotency-Key": `callback-${opts.formId}` },
        body: JSON.stringify({
          workspace_id: opts.workspaceId,
          phone_line_id: opts.lineId,
          to: opts.to,                       // UK number, e.g. 07700 900123
          consent_ref: `callback-form-${opts.formId}`,
        }),
      },
    );
    return { ok: true, status: data.status }; // "ringing_staff"
  } catch (e) {
    // e.g. "422 outside_hours: Calls can only be placed Monday to Saturday, 8am to 9pm UK time."
    return { ok: false, message: (e as Error).message };
  }
}

The same Idempotency-Key returns the original request, so double clicks never place two calls.

Which checks run before every call?

Every request is checked before anything rings, and a blocked request returns a clear code.

CodeMeaning
outside_hoursOnly Monday to Saturday, 8am–9pm UK time
suppressedThe number is on the workspace's do-not-call list
tps_listedThe number is registered on TPS or CTPS
tps_unavailableThe screening check could not run, so nothing was dialled (503)
spend_capThe workspace's monthly outbound limit is reached
daily_capThe key has made 50 requests today
line_not_owned / line_has_no_phoneThe line is not an active outbound line with a staff phone
invalid_numberNot a UK landline or mobile, or a premium-rate number

Screening against TPS/CTPS follows the ICO's guidance on marketing calls. Click-to-call is for customers who asked to be called — never use it for cold calling.

What happens on the phone?

Your staff phone rings first, showing your business line. When staff answer, Call Bullet dials the customer and connects them. If staff do not answer within about 30 seconds, the request ends as staff_missed and the customer is not called. The finished call appears in GET /workspaces/{id}/outbound-calls and its minutes are billed like other phone-line calls.

How should the button behave?

Small details make a callback button trustworthy.

  • Show calling hours next to the button and hide it outside them.
  • Validate the number as UK before submitting, and accept 07… and +44… formats.
  • Tell the customer “We're calling you now from 01706 …” once the request is accepted.
  • If the request is blocked, offer a time slot or a form instead.
  • Rate-limit the form itself, for example one request per number per hour, to stop abuse.

What prompt do I paste into my AI app builder?

This prompt builds the form and the server call.

AI build prompt · click-to-call
Add a "Call me back" button to this app using Call Bullet click-to-call.
- Docs: https://callbullet.com/developers/api.md (POST /calls/click-to-call). Use only documented fields.
- Store my key (cb_live_…, scopes workspaces:read, phone_lines:read, calls:place) as the server secret CALL_BULLET_API_KEY. Never call the API from the browser.
- Form: name and UK phone number, with a tick box "Please call me about my enquiry". Save the request with an id first.
- Server action: POST /calls/click-to-call with workspace_id, phone_line_id (from GET /workspaces/{id}/phone-lines), to, consent_ref = "callback-form-<id>" and Idempotency-Key = "callback-<id>".
- Show "We're calling you now" on success; on 422/503 show the error message and offer a booking form instead.
- Hide the button outside Monday–Saturday 8am–9pm UK time. Allow one request per phone number per hour.

How do I see whether the callback connected?

Each click-to-call request has a status your app can show, and the finished call is listed with your other outbound calls.

The request starts as ringing_staff. When staff answer it becomes connecting while the customer is dialled, then ended once the call finishes. If staff miss it, it ends as staff_missed and the customer is never rung. Show these as simple labels in your admin screen so the team can see which callbacks happened.

For reporting, read GET /workspaces/{id}/outbound-calls with a date range. Each callback appears as an outbound call from your business line, with whether it was answered and how long it lasted, so you can measure how quickly callback requests are handled during the working day.

When is click-to-call the right choice?

Use it when a customer has asked to be called and a person on your team should speak to them quickly.

Good examples are quote requests, booking enquiries outside business hours that you return first thing, or a “call me now” button on a high-value product page. A Manchester kitchen showroom can ring an enquiry back within a minute, from its own 0161 number, while the customer is still looking at designs. A solicitor's firm can return a web enquiry from the right office line so the client recognises the number next time.

It is not the right choice for lists of people who have not asked to be called, for automated or recorded messages, or for AI-led calls. Those need separate consent records and controls, and Call Bullet blocks them on this endpoint by design.

How do I handle a blocked request well?

Turn each block into a helpful next step instead of an error message. Outside calling hours, offer the next available time and tell the customer when to expect the call. When a number is on TPS or the do-not-call list, offer an email or booking form and let your team decide how to respond. If the spend cap is reached, alert an administrator rather than the customer. The error codes are stable, so your app can map each one to its own wording.

What does a typical callback look like?

From the customer pressing the button to talking with your team usually takes under a minute.

The request is checked and your staff phone starts ringing within a few seconds. When your colleague answers, Call Bullet dials the customer, who sees your business number and picks up as normal. If the customer does not answer, the call ends and appears as unanswered in the outbound history, so your team knows to try again later or send a text. Each request is stored with its consent reference, which gives you a clear record of why every callback was made.

Key takeaways

  • POST /calls/click-to-call rings your staff first, then the customer.
  • Hours, TPS, do-not-call, spend and daily caps are checked on every call.
  • calls:place must be switched on by itself.
  • Use an Idempotency-Key and only call customers who asked.

Frequently asked questions

Does an AI make the call?

No. Click-to-call always connects a person on your team. AI agents do not use this endpoint.

What number does the customer see?

Your business phone line's number.

Can I use it for sales calls to lists?

No. It is for customers who asked to be called. Calls to TPS-registered numbers are blocked.

How much does it cost?

Calls are billed as phone-line minutes like any other outbound call. The API request itself is free.

What if my staff don't answer?

The customer is not dialled and the request ends as staff_missed.

Can I see the call afterwards?

Yes. It appears in GET /workspaces/{id}/outbound-calls and in Call Bullet's call history.

See which marketing makes your phone ring

Start with one UK tracking number or a full website pool. Every call is recorded, transcribed and traced back to its source.