Call Bullet

Add an AI voice agent to an AI-built app

To add an AI voice agent to an AI-built app, create a draft with POST /agents using a Call Bullet key that has agents:write, attach a UK number, then finish testing and go-live in Call Bullet. Once live, read every call it handled, with summary and outcome, from GET /workspaces/{id}/agent-calls.

Last updated · Call Bullet

Why does the agent start as a draft?

An AI agent talks to real customers, so it must be tested before it answers a single call. Agents created through the API are always drafts, and the API cannot make them live. When the draft is ready, your app calls POST /agents/{id}/review-request to tell the workspace owner, then checks GET /agents/{id} until the status is live.

Going live happens in Call Bullet: you run test calls, review the answers, certify a version and start billing. Only a certified version can take calls, and every call uses that exact version. This keeps behaviour predictable and means a bug in your app can never put an untested agent on the phone.

What is the shortest path to a live agent?

From nothing to an agent answering calls:

  1. Create an API key with workspaces:read, agents:read, agents:write and numbers:read. agents:write must be switched on by itself.
  2. Create the draft with POST /agents: name, greeting and instructions.
  3. Attach a workspace number with POST /agents/{id}/numbers.
  4. Open the go_live_url returned by the API and run test calls in Call Bullet.
  5. Certify the version and complete checkout for the agent's tier.
  6. Read its calls in your app with GET /workspaces/{id}/agent-calls.

How do I create the draft agent?

The response always includes status: "draft", live: false and a link to finish setup.

TypeScript · create a draft agent
import { cb } from "./call-bullet.server";

export async function createAgent(workspaceId: string) {
  const { data } = await cb<{ data: { id: string; status: "draft"; live: false; go_live_url: string } }>(
    "/agents",
    {
      method: "POST",
      body: JSON.stringify({
        workspace_id: workspaceId,
        name: "Sam",
        greeting: "Hello, you've reached Pennine Plumbing. I'm Sam, how can I help?",
        instructions: "Take the caller's name, postcode and the problem. Offer the next free slot. Never quote prices.",
        business_info: "Plumbing and heating across Rochdale and Oldham, Mon–Sat 8am–6pm.",
        task: "Book plumbing visits",
      }),
    },
  );
  return data; // show data.go_live_url to the user
}

export async function attachNumber(agentId: string, trackingNumberId: string) {
  return cb(`/agents/${agentId}/numbers`, {
    method: "POST",
    body: JSON.stringify({ tracking_number_id: trackingNumberId, is_primary: true }),
  });
}

Edit the draft with PATCH /agents/{id}. Once the agent is live, the API returns 409 agent_not_draft and changes are made in Call Bullet.

How do I show what the agent did?

Agent calls include what the caller wanted, a summary and an outcome, ready for a follow-up list.

TypeScript · list agent calls
type AgentCall = { id: string; agent_id: string; caller_name: string | null; caller_request: string | null; outcome: string; urgency: string; summary: string | null };

export async function agentCalls(workspaceId: string, agentId: string) {
  const from = new Date(Date.now() - 7 * 864e5).toISOString();
  const { data } = await cb<{ data: AgentCall[] }>(
    `/workspaces/${workspaceId}/agent-calls?agent_id=${agentId}&from=${from}`,
  );
  return data.filter((c) => c.outcome === "lead"); // new enquiries to chase
}

Which permissions does each step need?

Ask only for what each feature needs.

StepEndpointPermission
Create draftPOST /agentsagents:write
Edit draftPATCH /agents/{id}agents:write
Attach numberPOST /agents/{id}/numbersagents:write
List agentsGET /workspaces/{id}/agentsagents:read
Read callsGET /workspaces/{id}/agent-callsagent_calls:read
Tasks and resultsGET /workspaces/{id}/agent-tasksagent_tasks:read

What does an AI voice agent cost?

Agents are billed by tier, each including a phone number and a monthly allowance of AI minutes; the current tiers are on the AI voice agents page. Drafts cost nothing, so your app can create and refine an agent before anyone pays.

Spend limits and a daily cap protect the account, and every action an agent takes is written to an audit log you can review in Call Bullet.

What prompt do I paste into my AI app builder?

This prompt builds the setup screen and stops at the draft.

AI build prompt · add a voice agent
Add an AI voice agent setup screen to this app using Call Bullet.
- Docs: https://callbullet.com/developers/api.md. Use only POST /agents, PATCH /agents/{id}, POST /agents/{id}/numbers, GET /workspaces/{id}/agents and GET /workspaces/{id}/agent-calls.
- Store my key (cb_live_…, scopes workspaces:read, numbers:read, agents:read, agents:write, agent_calls:read) as the server secret CALL_BULLET_API_KEY.
- Form fields: name, greeting, instructions, business info. On save, create or update the draft and show the returned go_live_url as a button: "Finish testing in Call Bullet".
- Show status clearly: draft until it is live. Never claim the agent is answering calls while status is draft.
- Add an "Agent calls" list with caller_request, summary and outcome for the last 7 days.

What should the agent's instructions include?

Good instructions read like a briefing for a new receptionist: what the business does, what to collect, what never to say and when to hand over. Keep facts such as opening hours and service areas in business_info, and behaviour in instructions. Avoid prices unless they are fixed, and tell the agent to take a message rather than guess. See the AI agents API guide for more examples.

How do I test the agent before it takes real calls?

Testing happens in Call Bullet, where you can call the agent yourself and review every answer before any customer hears it.

Open the go_live_url from the create response. Run a few test calls covering the questions customers really ask: opening hours, whether you cover a postcode, emergency call-outs, and something the agent should refuse. Each test call is recorded and transcribed, so you can read exactly what the agent said. Adjust the instructions, either in Call Bullet or with PATCH /agents/{id} while it is still a draft, and test again.

When the answers are right, certify the version. Certification freezes that exact set of instructions, so the version customers hear is the one you approved. Any later change creates a new version that has to be tested and certified again. This is slower than flipping a switch, but it means an agent's behaviour never changes without someone checking it first.

How do I hand calls from the agent to my team?

Set a fallback number so callers can reach a person when the agent cannot help, and use the call outcome to drive follow-ups in your app.

Pass fallback_number when creating the draft. Callers who ask for a human, or whose request the agent is told not to handle, are transferred there. Every call the agent handles is listed in GET /workspaces/{id}/agent-calls with the caller's request, a summary, an outcome such as lead and an urgency level.

A simple pattern is a follow-up list in your app: show every lead from the last day with the caller's name and request, and a button to ring them back. Urgent calls can trigger a notification so a manager sees a burst pipe or a cancelled appointment within minutes.

Is it safe to let my app create agents?

Yes, because the API can only create drafts, and drafts cannot answer or place calls.

The agents:write permission is off by default, even in the Everything preset, so it is only granted to keys that need it. Every agent created through the API is written to an audit log with the key that created it. A draft has no live version, so even if a bug in your app created a hundred drafts, none of them could speak to a customer. Taking an agent live always needs a person in Call Bullet to test it, certify it and start billing.

For agencies, this means a client portal can let business owners write their agent's greeting and instructions in your own interface, while the agency still controls the final go-live check. The owner sees their draft update immediately, and the agency reviews and certifies it before any calls are routed to it.

How long does it take end to end?

Creating the draft takes seconds and testing usually under an hour.

A developer can have a draft agent with a greeting, instructions and a number attached within ten minutes of creating the key. The owner then spends twenty to forty minutes in Call Bullet making test calls, refining the wording and certifying the version. After checkout, calls to the attached number reach the agent straight away, and the first real calls show up in GET /workspaces/{id}/agent-calls with their summaries a minute or two after they end. Being realistic about this timeline in your app avoids promising an owner that the agent is live when it is still a draft.

Key takeaways

  • POST /agents creates a draft; the API can never make an agent live.
  • Testing, certification and billing finish in Call Bullet via go_live_url.
  • agents:write must be switched on by itself.
  • Read results from GET /workspaces/{id}/agent-calls.

Frequently asked questions

Can my app make the agent live?

No. Agents made through the API are drafts. Going live needs test calls and certification in Call Bullet.

Can I edit a live agent through the API?

No. The API returns 409 agent_not_draft; edit live agents in Call Bullet so a new version is tested first.

Does a draft cost anything?

No. Billing starts when you take the agent live.

Can the agent use my existing number?

Yes. Attach any active number from the same workspace with POST /agents/{id}/numbers.

How do I see what callers asked for?

GET /workspaces/{id}/agent-calls returns caller_request, summary, outcome and urgency for each call.

Can the agent make outbound calls?

Outbound AI calling needs consent records, TPS screening and approval in Call Bullet; it is not started through the API.

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.