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

# API introduction

> Authenticate and make your first request to the Brosbots API

The public Brosbots REST API lets you do programmatically everything the
dashboard does: build and manage agents, run outbound campaigns, read
calls and usage, and manage numbers, tools, knowledge bases and
integrations.

## Base URL

```text theme={null}
https://app.brosbots.com/api/v1
```

## Authentication

Every request must include your organization's API key in the `X-API-Key`
header. You create and revoke keys in the dashboard:
click your account in the bottom-left corner of the sidebar, then **Brosbots API**.

```bash theme={null}
curl https://app.brosbots.com/api/v1/agents/summary \
  -H "X-API-Key: bb_live_..."
```

<Warning>
  Treat API keys like passwords: don't commit them to repositories and
  don't put them in frontend code. If a key leaks - revoke it immediately.
</Warning>

## Agent ID

Wherever a path contains `{agent_id}`, you can pass the agent's public
ID, e.g. `agent_7fK2mQ9xLp3RtV8wYb1N` (in the agent editor next to the
agent's name - click to copy), or its number. Both address the same agent.
In responses, the `workflow_id` field is the number.

<Note>
  The addresses in this reference (`/agents`, `/campaigns`, `/integrations`,
  `/triggers`, `/usage`, `/reports`) replace earlier ones such as
  `/workflow/{workflow_id}/calls` or `/organizations/usage/...`. The earlier
  addresses keep working unchanged, so existing integrations need no changes.
  Build new ones on the addresses in this reference. Field names in request and
  response bodies (such as `workflow_id`, `workflow_run_id`) have not changed.
</Note>

## Quick start: trigger a call

Start an outbound call with an existing agent. `phone_number` and
`initial_context` are sibling fields; the agent sees the variables in
`initial_context` in its prompts as `{{initial_context.<key>}}`.

```bash theme={null}
curl -X POST "https://app.brosbots.com/api/v1/agents/{agent_id}/calls" \
  -H "X-API-Key: bb_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+48123456789",
    "initial_context": { "first_name": "Jan" }
  }'
```

```json theme={null}
{ "status": "initiated", "workflow_run_id": 580, "workflow_run_name": "WR-API-4821" }
```

<Note>
  `POST /agents/{agent_id}/conversations` **does not place a call**. It only
  creates a run record for a browser session (`mode`: `webrtc`,
  `smallwebrtc`) or a chat (`chat`).
</Note>

## Reading a call

After the call ends, fetch the run (gathered data, duration, cost, SMS,
file links):

```bash theme={null}
curl "https://app.brosbots.com/api/v1/agents/{agent_id}/conversations/{conversation_id}" \
  -H "X-API-Key: bb_live_..."
```

| Field | Meaning |
| - | - |
| `duration_seconds` | Call length in whole seconds; `null` while the call is in progress |
| `gathered_context` | Data the agent gathered, including `call_disposition` |
| `recording_download_url` / `transcript_download_url` | Signed HTTPS links to the recording (WAV) and transcript (text). No API key needed |
| `download_urls_expire_at` | When the links expire (1 hour after the request). Fetch the run again for fresh ones |
| `recording_url` / `transcript_url` | Storage keys of the files (e.g. `recordings/580.wav`), **not URLs**. Kept for existing integrations |

The list `GET /agents/{agent_id}/conversations` returns `initial_context`,
`gathered_context` and `duration_seconds` for every call, so you don't need
to fetch each one. Download links, logs and SMS come only with a single run.

### Transcript

```bash theme={null}
curl "https://app.brosbots.com/api/v1/agents/{agent_id}/conversations/{conversation_id}/transcript" \
  -H "X-API-Key: bb_live_..."
```

```json theme={null}
{
  "run_id": 580,
  "segments": [
    { "role": "assistant", "text": "Good morning, this is the clinic.", "start": "2026-10-05T10:00:01+00:00", "end": "2026-10-05T10:00:02+00:00" },
    { "role": "user", "text": "I'd like to book a visit.", "start": "2026-10-05T10:00:05+00:00", "end": "2026-10-05T10:00:05+00:00" }
  ],
  "download_url": "https://...",
  "expires_at": "2026-10-05T11:00:00+00:00"
}
```

`role` is `user` (the caller) or `assistant` (the agent). Consecutive
fragments of one speaker are joined into one turn; `start` and `end` are the
timestamps of its first and last fragment (the file records no end of
speech). `download_url` is the raw text file, one fragment per line:

```text theme={null}
[2026-10-05T10:00:01+00:00] assistant: Good morning,
[2026-10-05T10:00:02+00:00] assistant: this is the clinic.
[2026-10-05T10:00:05+00:00] user: I'd like to book a visit.
```

### Recording

```bash theme={null}
curl "https://app.brosbots.com/api/v1/agents/{agent_id}/conversations/{conversation_id}/recording?expires_in=600" \
  -H "X-API-Key: bb_live_..."
```

Returns `download_url` (WAV), `content_type` and `expires_at`. `expires_in`
is the link's lifetime in seconds, from 60 to 86400 (default 3600). Both
endpoints return `404` while the call is in progress and the file isn't
saved yet, and when a retention policy has already deleted it.

## Deleting a call

```bash theme={null}
curl -X DELETE "https://app.brosbots.com/api/v1/agents/{agent_id}/conversations/{conversation_id}" \
  -H "X-API-Key: bb_live_..."
```

Returns `204`. Deletion is irreversible: the recording and transcript leave
storage, and the call loses its `initial_context` (including the phone
number), `gathered_context`, logs, the SMS sent during it and its
integration delivery records. The call disappears from the history and the
run endpoints return `404` for it. Its duration and cost stay in the
organization's billing records, as accounting law requires.

<Warning>
  Deleting doesn't recall data that has already left Brosbots: `call.completed`
  webhook payloads, CRM entries or sheet rows. Delete those on your side. A
  call in progress can't be deleted (`409`).
</Warning>

## Conventions

* Request and response bodies are JSON (`Content-Type: application/json`).
* Timestamps are ISO 8601 with a timezone.
* Lists are paginated with `page` / `limit` parameters; responses include
  `total_count` / `total_pages`.
* Errors use standard HTTP status codes with a JSON body:

```json theme={null}
{ "detail": "a human-readable reason" }
```

| Status | Meaning |
| - | - |
| `400` | Bad request (e.g. amount below minimum, invalid filter) |
| `401` | Missing or invalid API key |
| `404` | Resource doesn't exist or belongs to another organization |
| `409` | Conflict (e.g. resource already resolved) |
| `422` | Validation error - the body indicates the fields |
| `429` | Every outbound channel is busy - wait as many seconds as the `Retry-After` header says |
| `5xx` | Server error - idempotent requests can be retried |

## Limits

There is no fixed per-key request-rate limit today. `429` comes from the
endpoints that place calls (`POST /agents/{agent_id}/calls`,
`POST /triggers/{trigger_id}/calls`) when every outbound channel of the organization
is busy; the `Retry-After` header says how many seconds to wait. A call
outside 08:00-21:00 the recipient's local time ends in `409` with a
`Retry-After` header and a `detail.retry_at` field. A number on the
organization's Do not call list ends in `403` with a `detail` starting with
`do_not_call`.

Handle `429` generally: wait as long as `Retry-After` says, or back off
exponentially when the header is absent. A request-rate limit may be
introduced in the future.

## Interactive documentation

An always up-to-date, interactive reference (Swagger UI):
[`/api/v1/public-docs`](https://app.brosbots.com/api/v1/public-docs),
and the raw OpenAPI specification:
[`/api/v1/public-openapi.json`](https://app.brosbots.com/api/v1/public-openapi.json).


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