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

# Quickstart

> Complete your first authenticated REST API flow with a Brightalk API key.

Use the production base URL `https://api.brightalk.ai` from a trusted server. This flow creates one immediate asynchronous AI call and then retrieves the resulting call resource.

## 1. Create a scoped key

In [Brightalk API settings](https://www.brightalk.ai/settings/integrations/api), create a `bt_live_` key with both `calls:read` and `calls:write`. Those are the required least-privilege scopes for creating and polling a call. If you need to run the optional contact-creation example in step 2, also select `contacts:write`; omit that additional scope when you already have a contact in the same organization. The secret is displayed once, so copy it into your server-side secret manager immediately.

Set it as an environment variable without committing it to source control:

```bash theme={null}
export BRIGHTALK_API_KEY="your_brightalk_api_key"
```

## 2. Obtain an agent and contact reference

List eligible agents with `calls:read`. (`GET /agents` also accepts `batches:read`, but it is not needed for this call workflow.) Save one returned `id` as the `agent_id` for step 3.

Save every JavaScript sample as `.mjs` or run it in an ESM project. Top-level `await` requires ESM, and Node 18 or later provides the built-in `fetch` used here. Python samples use `requests`; in a clean environment, install it with `python -m pip install requests`.

<CodeGroup>
  ```curl theme={null}
  curl --request GET 'https://api.brightalk.ai/agents?limit=20' \
    --header "Authorization: Bearer $BRIGHTALK_API_KEY" \
    --header "Brightalk-Version: 2026-07-16"
  ```

  ```javascript theme={null}
  const response = await fetch("https://api.brightalk.ai/agents?limit=20", {
    method: "GET",
    headers: {
      Authorization: `Bearer ${process.env.BRIGHTALK_API_KEY}`,
      "Brightalk-Version": "2026-07-16",
    },
  });
  console.log(response.status, await response.json());
  ```

  ```python theme={null}
  import os
  import requests

  response = requests.request(
      "GET",
      "https://api.brightalk.ai/agents?limit=20",
      headers={
      "Authorization": f"Bearer {os.environ['BRIGHTALK_API_KEY']}",
      "Brightalk-Version": "2026-07-16",
      },
  )
  print(response.status_code, response.json())
  ```
</CodeGroup>

Next, use an existing contact's opaque `id` from the same organization. If you do not have one, the following `contacts:write` request creates or adopts a contact. It uses the reserved illustrative E.164 number `+12025550123`; replace the sample identity with controlled test data appropriate for your organization.

<CodeGroup>
  ```curl theme={null}
  curl --request POST 'https://api.brightalk.ai/contacts' \
    --header "Authorization: Bearer $BRIGHTALK_API_KEY" \
    --header "Brightalk-Version: 2026-07-16" \
    --header "Content-Type: application/json" \
    --data '{"external_id":"customer-8421","name":"Example Customer","phone_number":"+12025550123"}'
  ```

  ```javascript theme={null}
  const response = await fetch("https://api.brightalk.ai/contacts", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.BRIGHTALK_API_KEY}`,
      "Brightalk-Version": "2026-07-16",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({"external_id":"customer-8421","name":"Example Customer","phone_number":"+12025550123"}),
  });
  console.log(response.status, await response.json());
  ```

  ```python theme={null}
  import os
  import requests

  response = requests.request(
      "POST",
      "https://api.brightalk.ai/contacts",
      headers={
      "Authorization": f"Bearer {os.environ['BRIGHTALK_API_KEY']}",
      "Brightalk-Version": "2026-07-16",
      "Content-Type": "application/json",
      },
      json={"external_id":"customer-8421","name":"Example Customer","phone_number":"+12025550123"},
  )
  print(response.status_code, response.json())
  ```
</CodeGroup>

Contact creation returns `201` for a new contact or `200` for an existing or adopted contact. Save the response `id` as the `contact_id`. In step 3, replace `agt_demo_001` and `con_demo_001` with the agent and contact IDs returned above.

## 3. Create the call

The request needs `calls:write`, `Brightalk-Version`, and a nonsecret `Idempotency-Key`.

<Warning>
  Sending `POST /calls` with a reachable contact can place a real PSTN call. Confirm the recipient and timing before running a modified example.
</Warning>

<CodeGroup>
  ```curl theme={null}
  curl --request POST 'https://api.brightalk.ai/calls' \
    --header "Authorization: Bearer $BRIGHTALK_API_KEY" \
    --header "Brightalk-Version: 2026-07-16" \
    --header "Content-Type: application/json" \
    --header "Idempotency-Key: createCall-example-001" \
    --data '{"agent_id":"agt_demo_001","contact_id":"con_demo_001"}'
  ```

  ```javascript theme={null}
  const response = await fetch("https://api.brightalk.ai/calls", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.BRIGHTALK_API_KEY}`,
      "Brightalk-Version": "2026-07-16",
      "Content-Type": "application/json",
      "Idempotency-Key": "createCall-example-001",
    },
    body: JSON.stringify({"agent_id":"agt_demo_001","contact_id":"con_demo_001"}),
  });
  console.log(response.status, await response.json());
  ```

  ```python theme={null}
  import os
  import requests

  response = requests.request(
      "POST",
      "https://api.brightalk.ai/calls",
      headers={
      "Authorization": f"Bearer {os.environ['BRIGHTALK_API_KEY']}",
      "Brightalk-Version": "2026-07-16",
      "Content-Type": "application/json",
      "Idempotency-Key": "createCall-example-001",
      },
      json={"agent_id":"agt_demo_001","contact_id":"con_demo_001"},
  )
  print(response.status_code, response.json())
  ```
</CodeGroup>

A successful request returns `202 Accepted`. Save the `id` from the response:

```json theme={null}
{
  "id": "call_demo_001",
  "contact_id": "con_demo_001",
  "agent_id": "agt_demo_001",
  "queued_at": "2026-07-20T01:00:00Z",
  "created_at": "2026-07-20T01:00:00Z",
  "updated_at": "2026-07-20T01:00:00Z",
  "status": "queued",
  "answer_status": "unknown"
}
```

## 4. Poll the returned call ID

Replace `call_demo_001` with the `id` from step 3. Poll with `calls:read`; use backoff between requests and honor rate-limit headers.

<CodeGroup>
  ```curl theme={null}
  curl --request GET 'https://api.brightalk.ai/calls/call_demo_001' \
    --header "Authorization: Bearer $BRIGHTALK_API_KEY" \
    --header "Brightalk-Version: 2026-07-16"
  ```

  ```javascript theme={null}
  const response = await fetch("https://api.brightalk.ai/calls/call_demo_001", {
    method: "GET",
    headers: {
      Authorization: `Bearer ${process.env.BRIGHTALK_API_KEY}`,
      "Brightalk-Version": "2026-07-16",
    },
  });
  console.log(response.status, await response.json());
  ```

  ```python theme={null}
  import os
  import requests

  response = requests.request(
      "GET",
      "https://api.brightalk.ai/calls/call_demo_001",
      headers={
      "Authorization": f"Bearer {os.environ['BRIGHTALK_API_KEY']}",
      "Brightalk-Version": "2026-07-16",
      },
  )
  print(response.status_code, response.json())
  ```
</CodeGroup>

Continue while `status` is `queued`, `dialing`, or `in_progress`.

## 5. Interpret `status` and `answer_status`

`status` describes execution lifecycle. Stop polling when it is `completed`, `failed`, or `cancelled`. `answer_status` independently classifies what happened at the destination.

| Field           | Question it answers                                                 | Example values                                          |
| --------------- | ------------------------------------------------------------------- | ------------------------------------------------------- |
| `status`        | Did the call execution finish successfully, fail, or get cancelled? | `completed`, `failed`, `cancelled`                      |
| `answer_status` | Was the destination answered, unanswered, busy, or voicemail?       | `answered`, `no_answer`, `busy`, `voicemail`, `unknown` |

A normal no-answer result is `status: completed` with `answer_status: no_answer`; it is not a system failure. See [Call status lifecycles](/en/concepts/status-lifecycle) for every transition.
