## Braintrust API Overview

The Braintrust API allows you to interact with all aspects of the Braintrust platform programmatically. You can use it to:

- Create and manage projects, experiments, and datasets
- Log traces and metrics
- Manage prompts, tools, and scorers
- Configure access control and permissions
- Retrieve and analyze results

The API is defined by an OpenAPI specification published at [braintrust-openapi](https://github.com/braintrustdata/braintrust-openapi) on GitHub.

## Base URL

The base URL depends on your organization’s [data plane region](/content/docs/admin/organizations#data-plane-region/index.html):

| Region | Base URL |
| --- | --- |
| US | `https://api.braintrust.dev` |
| EU | `https://api-eu.braintrust.dev` |
| Self-hosted | Your custom data plane URL |

You can find your API URL in **Settings** > [**Data plane**](/content/app/~/configuration/org/api-url/index.html).

## Authentication

Authenticate requests with your API key in the Authorization header:

```
curl https://api.braintrust.dev/v1/project \
  -H "Authorization: Bearer $BRAINTRUST_API_KEY"
```

Create API keys in [Settings > API keys](/content/app/settings?subroute=api-keys/index.html).

## SDKs

While you can call the API directly, we recommend using one of our official SDKs:

[**TypeScript SDK** \
\
Official TypeScript/JavaScript SDK](/content/docs/sdks/typescript/quickstart/index.html)

[**Python SDK** \
\
Official Python SDK](/content/docs/sdks/python/quickstart/index.html)

[**Go SDK** \
\
Official Go SDK](/content/docs/sdks/go/quickstart/index.html)

[**Ruby SDK** \
\
Official Ruby SDK](/content/docs/sdks/ruby/quickstart/index.html)

[**Java SDK** \
\
Official Java SDK](/content/docs/sdks/java/quickstart/index.html)

[**C# SDK** \
\
Official C# SDK](/content/docs/sdks/csharp/quickstart/index.html)

[**Kotlin SDK** \
\
Official Kotlin SDK](https://github.com/braintrustdata/braintrust-kotlin)

## API resources

The API is organized around REST principles. Each resource has predictable URLs and uses HTTP response codes to indicate API errors.

### Project resources

- **Projects**: Organize your AI features and experiments
- **Experiments**: Run and track evaluation experiments
- **Datasets**: Manage test data for evaluations
- **Logs**: Store and query production traces
- **Prompts**: Version control your prompts
- **Functions**: Manage tools, scorers, and workflows
- **Evals**: Configure and run evaluations
- **Scores**: Define custom scoring functions
- **Tags**: Organize and filter project resources
- **Automations**: Configure automated workflows
- **Views**: Create and manage custom data views

### Organization resources

- **Organizations**: Manage your organization settings
- **Users**: Manage team members
- **Groups**: Organize users into teams
- **Roles**: Define permission levels
- **ACLs**: Configure fine-grained access control
- **API keys**: Manage authentication credentials
- **Service tokens**: Generate service-level authentication tokens

### Configuration resources

- **AI secrets**: Securely store API keys and credentials
- **Environment variables**: Manage environment-specific configuration
- **MCP servers**: Configure Model Context Protocol servers
- **Proxy**: Configure proxy settings for API requests

## Response format

All API responses are returned in JSON format. Successful responses will have a `2xx` status code, while errors will return `4xx` or `5xx` status codes with error details.

## Rate limits

The API uses rate limiting to ensure fair usage. Rate limits are applied per organization and endpoint. If you exceed the rate limit, you’ll receive a `429 Too Many Requests` response.

## Query data

Query your logs, experiments, and datasets with SQL through the `/btql` endpoint.

### Query logs and experiments

Use the `/btql` endpoint to query data with [SQL syntax](/content/docs/reference/sql/index.html). Data-source functions like `project_logs()` and `experiment()` accept an object name or its ID. See [Querying by name](/content/docs/reference/sql/query-structure#querying-by-name/index.html) for details. To control query lint warnings, set the lint_mode parameter — see [Lint warnings](/content/docs/reference/sql/best-practices#lint-warnings/index.html).

#### TypeScript Example

```typescript
const API_URL = "https://api.braintrust.dev/";
const headers = {
  Authorization: `Bearer ${process.env.BRAINTRUST_API_KEY}`,
};

const query = `
  SELECT id, input, output, scores
  FROM project_logs('your-project-id', shape => 'traces')
  WHERE scores.accuracy > 0.8
  LIMIT 100
`;

const response = await fetch(`${API_URL}/btql`, {
  method: "POST",
  headers,
  body: JSON.stringify({ query, fmt: "json" }),
});

const data = await response.json();
for (const row of data.data) {
  console.log(row);
}
```

#### Python Example

```python
import os
import requests

API_URL = "https://api.braintrust.dev/"
headers = {"Authorization": "Bearer " + os.environ["BRAINTRUST_API_KEY"]}

query = """
SELECT id, input, output, scores
FROM project_logs('your-project-id', shape => 'traces')
WHERE scores.accuracy > 0.8
LIMIT 100
"""

response = requests.post(
    f"{API_URL}/btql",
    headers=headers,
    json={"query": query, "fmt": "json"},
).json()

for row in response["data"]:
    print(row)
```

### Filter experiments by metadata

Filter experiments by metadata field equality using the `metadata` query parameter on [`GET /v1/experiment`](/content/docs/api-reference/experiments/get-experiment/index.html). Pass a JSON-serialized object to match experiments where all specified fields are equal — including nested paths:

#### Python Example

```python
import json
import os
import requests

API_URL = "https://api.braintrust.dev/v1"
headers = {"Authorization": "Bearer " + os.environ["BRAINTRUST_API_KEY"]}

response = requests.get(
    f"{API_URL}/experiment",
    headers=headers,
    params=dict(
        project_id="your-project-id",
        metadata=json.dumps({"env": "production", "model": {"name": "gpt-5-mini"}}),
    ),
)

experiments = response.json().get("objects", [])
for experiment in experiments:
    print(experiment["id"], experiment["name"])
```

### Fetch experiment results

Query experiments to check review status or other metrics:

#### Python Example

```python
import os
import requests

API_URL = "https://api.braintrust.dev/"
headers = {"Authorization": "Bearer " + os.environ["BRAINTRUST_API_KEY"]}

def fetch_experiment_review_status(experiment_id: str) -> dict:
    query = f"""
    SELECT
      sum(CASE WHEN scores."response quality" IS NOT NULL THEN 1 ELSE 0 END) AS reviewed,
      sum(CASE WHEN is_root THEN 1 ELSE 0 END) AS total
    FROM experiment('{experiment_id}')
    """

return requests.post(
        f"{API_URL}/btql",
        headers=headers,
        json={"query": query, "fmt": "json"},
    ).json()

EXPERIMENT_ID = "your-experiment-id"
print(fetch_experiment_review_status(EXPERIMENT_ID))
```

### Export data

Export logs, experiments, or datasets to JSON or Parquet:

#### Shell Script Example

```shell
# Export to JSON
curl https://api.braintrust.dev/btql \
  -H "Authorization: Bearer $BRAINTRUST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "SELECT * FROM project_logs(\"project-id\") traces",
    "fmt": "json"
  }' > export.json

# Export to Parquet
curl https://api.braintrust.dev/btql \
  -H "Authorization: Bearer $BRAINTRUST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "SELECT * FROM project_logs(\"project-id\") traces",
    "fmt": "parquet"
  }' > export.parquet
```

## Write and manage data

### Run experiments

Create and run experiments programmatically:

#### Python Example

```python
import os
from uuid import uuid4
import requests

API_URL = "https://api.braintrust.dev/v1"
headers = {"Authorization": "Bearer " + os.environ["BRAINTRUST_API_KEY"]}

# Create a project
project = requests.post(
    f"{API_URL}/project",
    headers=headers,
    json={"name": "My Project"}
).json()

# Create an experiment
experiment = requests.post(
    f"{API_URL}/experiment",
    headers=headers,
    json={"name": "Test Run", "project_id": project["id"]}
).json()

# Insert experiment results
for i in range(10):
    requests.post(
        f"{API_URL}/experiment/{experiment['id']}/insert",
        headers=headers,
        json={
            "events": [{
                "id": uuid4().hex,
                "input": {"question": f"Test {i}"},
                "output": f"Answer {i}",
                "scores": {"accuracy": 0.9}
            }]
        }
    )
```

### Log programmatically

Insert logs via the API:

#### Python Example

```python
import os
from uuid import uuid4
import requests

API_URL = "https://api.braintrust.dev/v1"
headers = {"Authorization": "Bearer " + os.environ["BRAINTRUST_API_KEY"]}

# Get or create project
project = requests.post(
    f"{API_URL}/project",
    headers=headers,
    json={"name": "My Project"}
).json()

# Insert log event
requests.post(
    f"{API_URL}/project_logs/{project['id']}/insert",
    headers=headers,
    json={
        "events": [{
            "id": uuid4().hex,
            "input": {"question": "What is 2+2?"},
            "output": "4",
            "scores": {"accuracy": 1.0},
            "metadata": {"environment": "production"}
        }]
    }
)
```

### Delete logs

Mark logs for deletion by setting `_object_delete`:

#### Python Example

```python
import os
import requests

API_URL = "https://api.braintrust.dev/"
headers = {"Authorization": "Bearer " + os.environ["BRAINTRUST_API_KEY"]}

# Find logs to delete
query = """
SELECT id
FROM project_logs('project-id', shape => 'traces')
WHERE metadata.user_id = 'test-user'
"""

response = requests.post(
    f"{API_URL}/btql",
    headers=headers,
    json={"query": query}
).json()

ids = [row["id"] for row in response["data"]]

# Delete logs
delete_events = [{"id": id, "_object_delete": True} for id in ids]
requests.post(
    f"{API_URL}/v1/project_logs/project-id/insert",
    headers=headers,
    json={"events": delete_events}
)
```

## Impersonate users

User impersonation lets a privileged user perform an operation on behalf of another user, using the impersonated user’s identity and permissions. To impersonate a user, set the `x-bt-impersonate-user` header to the ID or email of the user you want to impersonate.

#### TypeScript Example

```typescript
// If you're self-hosting Braintrust, then use your stack's Universal API URL, e.g.
//   https://dfwhllz61x709.cloudfront.net
export const BRAINTRUST_API_URL = "https://api.braintrust.dev";
export const API_KEY = process.env.BRAINTRUST_API_KEY;

async function main() {
    const response = await fetch(`${BRAINTRUST_API_URL}/v1/project`, {
        method: "POST",
        headers: {
            "Authorization": `Bearer ${API_KEY}`,
            "x-bt-impersonate-user": process.env.USER_EMAIL,
        },
        body: JSON.stringify({
            name: "my-project",
            org_name: process.env.ORG_NAME,
        }),
    });
    console.log(await response.json());
}
main();
```

### Next steps

- Explore the [complete API reference](/content/docs/api-reference/index.html) for all available endpoints.
- Learn about [SQL querying](/content/docs/reference/sql/index.html) to analyze your data.
- Review [system limits](/content/docs/plans-and-limits/index.html) for API usage constraints.
- Check out the [Python SDK](/content/docs/sdks/python/versions/latest/index.html) or [TypeScript SDK](/content/docs/sdks/typescript/versions/latest/index.html) documentation.
