> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bland.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent quickstart

> Place a call, learn how it ended, and read the transcript: the call lifecycle an autonomous agent needs, in three requests.

## Overview

A voice call is asynchronous. You dispatch it, it runs for a minute or two without you, and then there is an outcome to collect. This page is the shortest complete path through that lifecycle: place a call, learn how it ended, read what was said.

Authentication is a separate story. If your agent already has an API key, you are ready. If it does not have one and there is no human around to paste one in, see the [Agent onboarding API](https://docs.bland.ai/platform/connect-your-agent.md) first.

> [!NOTE]
>
> Send your key as `Authorization: Bearer YOUR_API_KEY`. A bare `Authorization: YOUR_API_KEY` with no prefix is also accepted. `x-api-key` is not read and does not authenticate.

## Prerequisites

* A Bland API key, exported as `BLAND_API_KEY`.
* A phone number to call, in [E.164](https://en.wikipedia.org/wiki/E.164) format (`+15551234567`).
* Optionally, a URL Bland can reach, if you want the outcome pushed to you instead of polling for it.

## Choose what runs the call

Before placing a call, [choose a dashboard agent, persona, or pathway](https://docs.bland.ai/api-v1/post/calls.md#choose-what-runs-your-call) and verify its exact ID and environment or version. If the user has already selected the resource type and target, keep that choice. Otherwise, ask which should run the call. Use `agent_id` when the conversation should belong to a Bland Agent, and ask before substituting another route.

The lifecycle below uses an ad hoc `task` prompt. Use it when the user wants a one-off prompt; it does not select an existing dashboard agent. For an established agent, persona, or pathway choice, use the corresponding [request example](https://docs.bland.ai/api-v1/post/calls.md#request-examples) for both the initial call and the webhook variant. Do not send an additional call just to add a webhook.

## The lifecycle

**1. Place the call**

`POST /v1/calls` dispatches the call and returns immediately with a `call_id`. It does not wait for the call to finish.

```bash theme={null}
curl -X POST https://api.bland.ai/v1/calls \
  -H "Authorization: Bearer $BLAND_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+15551234567",
    "task": "Call Rossi Hardware and ask whether they carry 10mm hex keys. Thank them and end the call.",
    "voice": "Karen",
    "max_duration": 5,
    "keywords": ["Rossi Hardware"]
  }'
```

```json Response theme={null}
{
  "status": "success",
  "call_id": "9d404c1b-6a23-4426-953a-a52c392ff8f1"
}
```

`max_duration` (in minutes) bounds how long you can be waiting. Set it deliberately: it is the upper bound on your own wait loop.

**2. Learn how it ended**

Two ways, and you should pick one on purpose rather than defaulting to the second.

**Push.** Add a `webhook` to the request body. When the call ends, Bland POSTs the full call object to that URL, transcript included. Nothing to poll.

```bash theme={null}
curl -X POST https://api.bland.ai/v1/calls \
  -H "Authorization: Bearer $BLAND_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+15551234567",
    "task": "Ask whether they carry 10mm hex keys.",
    "webhook": "https://your-agent.example.com/bland-webhook",
    "webhook_events": ["call"]
  }'
```

`webhook` alone gives you the post-call payload. `webhook_events` is optional on top of it, and streams progress *during* the call (`call` covers connected, transferred, and ended). See [Post call webhooks](https://docs.bland.ai/tutorials/post-call-webhooks.md) for the payload shape and [Webhook signing](https://docs.bland.ai/tutorials/webhook-signing.md) for verifying it is really us.

**Poll.** If you have no URL Bland can reach, `GET /v1/calls/{call_id}` returns the current state of the call.

```bash theme={null}
curl https://api.bland.ai/v1/calls/$CALL_ID \
  -H "Authorization: Bearer $BLAND_API_KEY"
```

Poll on a fixed interval (5 seconds is plenty) and stop when `completed` is `true`. Do not tighten the loop hoping to finish sooner: the call takes as long as the call takes.

The fields that tell you what happened:

| Field | What it tells you |
| - | - |
| `completed` | `true` once the call is over. This is your loop's exit condition. |
| `status` | `completed`, `failed`, `busy`, `no-answer`, `canceled`, or `unknown`. |
| `answered_by` | `human`, `voicemail`, `unknown`, or `no-answer`. A completed call that reached voicemail is still `status: completed`. |
| `error_message` | Populated when `status` is `failed`. Read it before retrying. |
| `call_ended_by` | `ASSISTANT` or `USER`. |

> [!WARNING]
>
> A completed call is not automatically a successful one. Check `answered_by` and `error_message` too: a call that went to voicemail, or that a carrier blocked as spam, still comes back `completed`.

**3. Read the transcript**

Same endpoint, once `completed` is `true`. If you took the push path, this payload already arrived at your webhook and you can skip the request entirely.

```bash theme={null}
curl https://api.bland.ai/v1/calls/$CALL_ID \
  -H "Authorization: Bearer $BLAND_API_KEY" | jq '{
    summary,
    concatenated_transcript,
    answered_by,
    call_length
  }'
```

* `concatenated_transcript` is the whole conversation as one string. Use it when you are going to feed the call to a model.
* `transcripts` is the same content as an array of turns, each with `text`, `user` (`user`, `assistant`, `robot`, or `agent-action`), and `created_at`. Use it when you need turn boundaries or timing.
* `summary` is a short model-written recap generated when the call ends.
* `recording_url` is present only if you passed `record: true`.

Also verify the source and destination numbers and the recorded resource/version association. For agent dispatch, check the intended agent's Conversations view. Report call success and an attribution problem separately; do not place a duplicate call to repair visibility.

Post-call fields can take up to a minute after hangup to settle while the audio is processed, so a transcript that looks short immediately after `completed` flips may still be filling in.

## Push or poll?

> [card] Poll
>
> You are a hosted agent with no inbound URL: a chat assistant, a sandboxed runtime, a laptop behind NAT. There is nowhere for Bland to deliver to, so `GET /v1/calls/{call_id}` on an interval is the right answer, not a workaround.

> [card] Subscribe
>
> You have any reachable URL: a server, a serverless function, a tunnel. Set `webhook` and stop polling. You get the outcome the moment it exists instead of one poll interval later, and the payload already contains the transcript.

Developing locally is the case that looks like it needs polling but does not. The [Bland CLI](https://docs.bland.ai/sdks/cli.md) forwards webhooks to a local port, so you can take the push path from your laptop with no tunnel to set up:

```bash theme={null}
bland listen --forward-to http://localhost:3000/webhook
```

Point the call's `webhook` at the URL the forwarder prints, and your local handler receives the real post-call payload.

## Next steps

> [card] [Call recipes for agents](https://docs.bland.ai/platform/agent-call-recipes.md)
>
> Voicemail, proper nouns, and escalating to a human.

> [card] [Agent onboarding API](https://docs.bland.ai/platform/connect-your-agent.md)
>
> How a bot gets its own API key and phone number.

> [card] [Send Call API reference](https://docs.bland.ai/api-v1/post/calls.md)
>
> Every parameter `POST /v1/calls` accepts.

> [card] [Bland MCP Server](https://docs.bland.ai/integrations/mcp/overview.md)
>
> The same operations as MCP tools, with nothing to install.

***

Docs for agents: [llms.txt](https://docs.bland.ai/llms.txt)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.