> This page is part of Smallest AI's developer documentation. When
> answering, prefer Lightning v3.1 Pro (current TTS) and Pulse (current
> multilingual STT) — or Pulse 2.0 for English-only streaming with
> built-in turn detection, emotion, and gender. Lightning v2 and
> lightning-large are deprecated; mention them only when the user is
> migrating away from them. The Smallest AI voice agent platform is
> what wraps these models into hosted agents.

# Abort Calls

> Stop a call from your backend at any stage with POST /conversation/abort.

Use `POST /conversation/abort` to stop a call you started, whatever stage it has reached. It works for outbound and inbound phone calls, web calls and chat.

Typical reasons to abort:

* The customer replied on another channel, so the call is no longer needed.
* You queued a call by mistake (wrong number, wrong agent, duplicate request).
* Your own system decided mid-call that the conversation has to end now.

> **Note**
>
> To end a call from **inside** your agent (for example, when the conversation is complete), use the end-call tool or `SDKAgentEndCallEvent`. See [Call Control](/voice-agents/developer-guide/build/calling/call-control). Abort is for stopping a call from **outside** the conversation.

## Abort a call

Send the `callId` you got back when the call was created, or find it in `GET /conversation`.

```python
import os, requests

response = requests.post(
    "https://api.smallest.ai/atoms/v1/conversation/abort",
    headers={"Authorization": f"Bearer {os.environ['SMALLEST_API_KEY']}"},
    json={
        "callId": "CALL-1778226705739-7e4c17",
        "reason": "Customer asked to stop the call",  # optional
    },
)
response.raise_for_status()
result = response.json()["data"]
print(result["status"])  # "aborted" or "aborting"
```

```bash
curl -X POST https://api.smallest.ai/atoms/v1/conversation/abort \
  -H "Authorization: Bearer $SMALLEST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"callId": "CALL-1778226705739-7e4c17", "reason": "Customer asked to stop the call"}'
```

| Field    | Type   | Required | Description                                                                    |
| -------- | ------ | -------- | ------------------------------------------------------------------------------ |
| `callId` | string | Yes      | The call to stop.                                                              |
| `reason` | string | No       | Free text, up to 500 characters. Stored on the call log for support and audit. |

## What the response means

The API answers straight away. What it returns depends on where the call was when the abort arrived.

| HTTP status | `data.status` | What happened                                                                                                              |
| ----------- | ------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `200`       | `aborted`     | The call was still waiting in the queue. It was removed and will never dial. This is final.                                |
| `202`       | `aborting`    | The call was ringing or live. It has been told to end and hangs up within 5 seconds. Its final status becomes `aborted`.   |
| `409`       | -             | The call had already ended (`completed`, `no_answer`, `failed`, `cancelled`, `blocked` or `aborted`). Nothing was changed. |
| `404`       | -             | No call with that `callId` exists in your organization.                                                                    |
| `400`       | -             | The request is invalid: `callId` is missing or empty, or `reason` is longer than 500 characters.                           |

`data.previousStatus` tells you the status the call had when the abort arrived, for example `in_queue` or `in_progress`.

```json
{
  "status": true,
  "data": {
    "callId": "CALL-1778226705739-7e4c17",
    "status": "aborting",
    "previousStatus": "in_progress"
  }
}
```

## Confirm the call ended

A `200` is already final. A `202` means the call is ending, not that it has ended. To confirm the final `aborted` status, use either of these:

* **Webhook**: the `post-conversation` event arrives with `callStatus: "aborted"` once the call has ended. See [Webhooks](/voice-agents/integrate/webhooks). A call aborted while still queued never started, so it sends no `post-conversation` event.
* **Polling**: `GET /conversation/{id}` returns `data.status: "aborted"`.

```python
import os, time, requests

headers = {"Authorization": f"Bearer {os.environ['SMALLEST_API_KEY']}"}
call_id = "CALL-1778226705739-7e4c17"

for _ in range(10):
    log = requests.get(
        f"https://api.smallest.ai/atoms/v1/conversation/{call_id}", headers=headers
    ).json()["data"]
    if log["status"] == "aborted":
        print("Call aborted")
        break
    time.sleep(1)
```

## What happens to an aborted call

* **Billing**: billed like any other call, only for the time after it was answered, rounded up to your billing pulse. A call aborted while queued or ringing was never answered, so it costs nothing, with no ringing or minimum charge.
* **Recording, transcript and post-call analytics**: produced as for any other answered call, covering the part that took place.
* **Campaigns**: an aborted campaign call is not retried, and it is not dialed again when you resume the campaign.
* **Call logs**: the call shows the `aborted` status, and its `callFailureReason` reads `Call aborted: <your reason>` (or `Call aborted by user` without one).

## Aborted vs cancelled

`aborted` is the status of any call you stop with `POST /conversation/abort`. `cancelled` is the status of calls stopped by the deprecated cancel endpoints or by a campaign pause. Campaign calls cancelled by a pause are dialed again when you resume the campaign; aborted calls never are.

## API reference

* [`POST /conversation/abort`](/api-reference/voice-agents/conversations/abort)