API Reference - Braintrust

Braintrust API Overview

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

The API is defined by an OpenAPI specification published at braintrust-openapi on GitHub.

Base URL

The base URL depends on your organization’s data plane region:

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.

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.

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

Organization resources

Configuration resources

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. Data-source functions like project_logs() and experiment() accept an object name or its ID. See Querying by name for details. To control query lint warnings, set the lint_mode parameter — see Lint warnings.

TypeScript Example

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

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. Pass a JSON-serialized object to match experiments where all specified fields are equal — including nested paths:

Python Example

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

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

# 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

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

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

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

// 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