> This page is for Cloud Call Center.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.hams.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.hams.ai/_mcp/server.

# List calls

GET https://telephony.hams.ai/api/developer/v1/cdrs

List the call detail records of the whole account. The list is cursor-paginated. The newest call is first. Filters: direction, outcome, agent extension, call start range, number, and duration. Without `from`, the list has only the calls of the last 7 days. A range of more than 92 days returns 422. A `from` value after `to` also returns 422.

Reference: https://docs.hams.ai/cloud-call-center/reference/call-history/list-calls

## Authentication

- `Authorization` header (bearer token, required) — An API key. Send it as `Authorization: Bearer ccc_live_…`

## Request

### Query parameters

- `cursor` (string, optional, nullable) — The cursor from the previous page. Do not change it
- `limit` (integer, optional, default: 25)
- `include_total` (boolean, optional, default: false) — Add an exact count to the response. This causes an extra query
- `direction` (enum, optional, nullable) — The direction of the call
  - Allowed values: `inbound`, `outbound`, `internal`
- `outcome` (enum, optional, nullable) — The outcome of the call
  - Allowed values: `answered`, `no_answer`, `busy`, `abandoned`, `canceled`, `failed`, `voicemail`
- `agent` (string, optional, nullable) — The extension number of the agent that handled the call
- `from` (datetime, optional, nullable) — Only calls that start at or after this time. The value must include a timezone. Without it, the API returns 422
- `to` (datetime, optional, nullable) — Only calls that start before this time. The value must include a timezone. Without it, the API returns 422. The default is now
- `number` (string, optional, nullable) — A substring of the caller number or the callee number
- `min_duration` (integer, optional, nullable) — The minimum value of `total_seconds`
- `max_duration` (integer, optional, nullable) — The maximum value of `total_seconds`

## Response

### 200

Successful Response

- `data` (list of CdrRead, required)
- `has_more` (boolean, required)
- `next_cursor` (string, optional, nullable)
- `total_count` (integer, optional, nullable)

## Errors

### 401 Unauthorized Error

The key is missing, revoked, expired, or not a developer key

- `detail` (string, required) — A message for a person. It can change at any time.
- `code` (string, required) — A stable key for a program, for example `validation_error` or `rate_limited`.
- `support_id` (string, required) — A short id to quote when you contact support.
- `errors` (list of ErrorResponseErrorsItems, optional) — The field errors. Present only for validation failures.

### 422 Unprocessable Entity Error

The request failed validation

- `detail` (string, required) — A message for a person. It can change at any time.
- `code` (string, required) — A stable key for a program, for example `validation_error` or `rate_limited`.
- `support_id` (string, required) — A short id to quote when you contact support.
- `errors` (list of ErrorResponseErrorsItems, optional) — The field errors. Present only for validation failures.

### 429 Too Many Requests Error

The request exceeds a rate limit. The `Retry-After` header gives the time when the window ends

- `detail` (string, required) — A message for a person. It can change at any time.
- `code` (string, required) — A stable key for a program, for example `validation_error` or `rate_limited`.
- `support_id` (string, required) — A short id to quote when you contact support.
- `errors` (list of ErrorResponseErrorsItems, optional) — The field errors. Present only for validation failures.

## Types

### CdrRead

One call detail record. The `id` is the one id of the call. It is the same id in webhooks and on the live board.

- `id` (string, required)
- `started_at` (datetime, required)
- `direction` (string, optional, nullable)
- `outcome` (enum, optional, nullable) — How the call ended.
  - Allowed values: `answered`, `no_answer`, `busy`, `abandoned`, `canceled`, `failed`, `voicemail`
- `outcome_detail` (string, optional, nullable) — The reason for the outcome. Examples are `direct`, `queue`, `external`, `voice_agent`, and `agent_no_answer`. New values can appear. Treat an unknown value as information only.
- `from_number` (string, optional, nullable) — The caller number. On an outbound call, it is the caller ID that the carrier saw.
- `from_type` (string, optional, nullable)
- `to_number` (string, optional, nullable) — The callee number. On an outbound call, it is the number that the system dialed.
- `to_type` (string, optional, nullable)
- `answered_at` (datetime, optional, nullable)
- `ended_at` (datetime, optional, nullable)
- `total_seconds` (integer, optional, nullable)
- `talk_seconds` (integer, optional, nullable)
- `ring_seconds` (integer, optional, nullable)
- `queue_wait_seconds` (integer, optional, nullable)
- `queue_handled` (boolean, optional, nullable)
- `queues_touched` (integer, optional, nullable)
- `agent_user_id` (string, optional, nullable)
- `agent_extension_snapshot` (string, optional, nullable)
- `agent_name_snapshot` (string, optional, nullable)
- `data_quality` (string, optional, nullable) — `complete` means the record is final. `partial` means the carrier record of the call has not arrived yet, and the timings can still change. `conflicted` means the engine recorded an answer but the queue recorded an abandon.
- `account_id` (string, optional, nullable)
- `domain_id` (string, optional, nullable)
- `did_id` (string, optional, nullable)
- `trunk_id` (string, optional, nullable)
- `recording_id` (string, optional, nullable)
- `recording_status` (string, optional, nullable)
- `transcript_status` (enum, optional, nullable) — The state of the transcript of the recording of the call.
  - Allowed values: `pending`, `ready`, `failed`, `skipped`
- `transcript_error` (enum, optional, nullable) — The reason a transcript failed.
  - Allowed values: `too_long`, `unavailable`
- `analysis_status` (enum, optional, nullable) — The state of the post-call analysis of the call. `null` when the call has no analysis.
  - Allowed values: `pending`, `completed`, `skipped`, `failed`
- `analysis_outcome` (enum, optional, nullable) — How the call ended for the customer, from the analysis. `null` until the analysis is complete.
  - Allowed values: `resolved`, `unresolved`, `escalated`, `customer_silent`
- `analysis_sentiment_end` (enum, optional, nullable) — The mood of the customer at the end of the call, from the analysis.
  - Allowed values: `very_negative`, `negative`, `neutral`, `positive`, `very_positive`
- `analysis_agent_score` (integer, optional, nullable) — The score of the human agent, 1 to 5. `null` when no human agent spoke on the call.
- `analysis_labels` (list of string, optional, nullable) — The labels that the analysis picked from the labels of its profile.

### ErrorResponseErrorsItems

- `field` (string, optional)
- `message` (string, optional)
- `type` (string, optional)

## Examples

**Response**

```json
{
  "data": [
    {
      "id": "string",
      "started_at": "2024-01-15T09:30:00Z",
      "direction": "string",
      "outcome": "answered",
      "outcome_detail": "string",
      "from_number": "string",
      "from_type": "string",
      "to_number": "string",
      "to_type": "string",
      "answered_at": "2024-01-15T09:30:00Z",
      "ended_at": "2024-01-15T09:30:00Z",
      "total_seconds": 1,
      "talk_seconds": 1,
      "ring_seconds": 1,
      "queue_wait_seconds": 1,
      "queue_handled": true,
      "queues_touched": 1,
      "agent_user_id": "string",
      "agent_extension_snapshot": "string",
      "agent_name_snapshot": "string",
      "data_quality": "string",
      "account_id": "string",
      "domain_id": "string",
      "did_id": "string",
      "trunk_id": "string",
      "recording_id": "string",
      "recording_status": "string",
      "transcript_status": "pending",
      "transcript_error": "too_long",
      "analysis_status": "pending",
      "analysis_outcome": "resolved",
      "analysis_sentiment_end": "very_negative",
      "analysis_agent_score": 1,
      "analysis_labels": [
        "string"
      ]
    }
  ],
  "has_more": true,
  "next_cursor": "string",
  "total_count": 1
}
```

**SDK Code**

```python
import requests

url = "https://telephony.hams.ai/api/developer/v1/cdrs"

headers = {"Authorization": "Bearer <token>"}

response = requests.get(url, headers=headers)

print(response.json())
```

```javascript
const url = 'https://telephony.hams.ai/api/developer/v1/cdrs';
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://telephony.hams.ai/api/developer/v1/cdrs"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://telephony.hams.ai/api/developer/v1/cdrs")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://telephony.hams.ai/api/developer/v1/cdrs")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://telephony.hams.ai/api/developer/v1/cdrs', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://telephony.hams.ai/api/developer/v1/cdrs");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://telephony.hams.ai/api/developer/v1/cdrs")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```