> This page is for Agent Handler.

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

# List tool call logs

GET https://ah-api.merge.dev/api/v1/logs/tool-calls/

Returns a cursor-paginated page of the organization's tool call logs, ordered oldest-first. Poll repeatedly, passing the returned `next_cursor` as `cursor`, until `has_more` is false. Only the last 30 days of logs are available. Credential values in headers (e.g. Authorization, API keys) are redacted. This endpoint is available on the Enterprise plan. Contact your account team to enable it.

Reference: https://docs.merge.dev/merge-agent-handler/agent-handler/logs/tool-calls

## Authentication

- `Authorization` header (bearer token, required) — Token-based authentication with required prefix "Bearer"

## Request

### Query parameters

- `client_trace_id` (string, optional) — Exact match on the caller's W3C traceparent trace id (32 hex). The Merge Gateway request log records the same value on the model requests of the same prompt, so one id joins the two logs.
- `connector_id` (string, optional) — Filter by connector ID.
- `created_after` (datetime, optional) — Only logs at or after this timestamp (ISO 8601). Clamped to the last 30 days — older values are raised to the 30-day floor.
- `created_before` (datetime, optional) — Only logs at or before this timestamp (ISO 8601).
- `cursor` (string, optional) — Opaque cursor from a previous response's `next_cursor`.
- `error_reason` (string, optional) — Exact match on why execution failed (e.g. tool_execution_error, reauth_required, blocked_by_security_rule). Executed calls only; refusals decided before execution are not logged as tool calls.
- `page_size` (integer, optional) — Records per page (1-1000, default 100).
- `status` (string, optional) — Filter by execution status.
- `tool_name` (string, optional) — Filter by tool name (partial match).
- `turn_id` (string, optional) — Exact match on the agent turn id: the caller's X-Merge-Turn-Id, else Codex CLI's turn id. Also recorded on the Gateway request log.

## Response

### 200

- `results` (list of ToolCallLogPublic, required)
- `next_cursor` (string, required, nullable)
- `has_more` (boolean, required)

## Types

### ToolCallLogPublic

A single tool-call log record. Strict subset of the internal toolcall payload (see ``ToolcallDocument.to_api_dict``); omits the hydrated connector/tool_pack/ registered_user objects and exposes their raw IDs instead.

- `id` (string, required)
- `created_at` (datetime, required)
- `started_at` (datetime, optional, nullable)
- `ended_at` (datetime, optional, nullable)
- `registered_user_id` (string, optional, nullable)
- `connector_id` (string, optional, nullable)
- `connector_source` (string, optional, nullable)
- `tool_pack_id` (string, optional, nullable)
- `tool_name` (string, optional, nullable)
- `tool_args` (string, optional, nullable)
- `result` (string, optional, nullable)
- `headers` (string, optional, nullable)
- `status` (string, optional, nullable)
- `client_trace_id` (string, optional, nullable)
- `turn_id` (string, optional, nullable)
- `error_reason` (enum, optional, nullable)
  - Allowed values: `reauth_required`, `token_refreshed_retryable`, `billing_limit_reached`, `tool_not_found`, `invalid_arguments`, `unsupported_operation`, `tool_execution_error`, `blocked_by_security_rule`, `blocked_by_guardrail`, `permission_denied`, `internal_server_error`

## Examples

**Response**

```json
{
  "results": [
    {
      "id": "string",
      "created_at": "2024-01-15T09:30:00Z",
      "started_at": "2024-01-15T09:30:00Z",
      "ended_at": "2024-01-15T09:30:00Z",
      "registered_user_id": "string",
      "connector_id": "string",
      "connector_source": "string",
      "tool_pack_id": "string",
      "tool_name": "string",
      "tool_args": "string",
      "result": "string",
      "headers": "string",
      "status": "string",
      "client_trace_id": "string",
      "turn_id": "string",
      "error_reason": "reauth_required"
    }
  ],
  "next_cursor": "string",
  "has_more": true
}
```

**SDK Code**

```python
import requests

url = "https://ah-api.merge.dev/api/v1/logs/tool-calls/"

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

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

print(response.json())
```

```javascript
const url = 'https://ah-api.merge.dev/api/v1/logs/tool-calls/';
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://ah-api.merge.dev/api/v1/logs/tool-calls/"

	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://ah-api.merge.dev/api/v1/logs/tool-calls/")

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://ah-api.merge.dev/api/v1/logs/tool-calls/")
  .header("Authorization", "Bearer <token>")
  .asString();
```

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

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://ah-api.merge.dev/api/v1/logs/tool-calls/', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

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

```csharp
using RestSharp;

var client = new RestClient("https://ah-api.merge.dev/api/v1/logs/tool-calls/");
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://ah-api.merge.dev/api/v1/logs/tool-calls/")! 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()
```