The Braintrust Data API provides programmatic access to all platform features through a REST interface. Use it to invoke functions, query logs, manage datasets, run experiments, and integrate Braintrust into your workflows.
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.
Invoke functions
Call prompts, tools, or scorers via the /v1/function endpoint:
curl https://api.braintrust.dev/v1/function \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BRAINTRUST_API_KEY" \
-d '{
"project_name": "My Project",
"slug": "summarizer",
"input": {
"text": "Long text to summarize..."
}
}'
Parameters
project_name or project_id: Project containing the function
slug: Function slug
input: Function input parameters
version (optional): Pin to a specific version
environment (optional): Use environment-specific version
stream (optional): Enable streaming responses
Response
{
"output": "Summarized text here...",
"metadata": {
"model": "claude-3-5-sonnet-latest",
"tokens": 150,
"latency": 0.85
}
}
Query logs and experiments
Use the /btql endpoint to query data with SQL syntax:
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)
SQL syntax
Query data using standard SQL syntax or BTQL’s alternative pipe-delimited syntax:
SELECT input, output, scores.accuracy
FROM project_logs('project-id', shape => 'traces')
WHERE metadata.environment = 'production'
AND scores.accuracy < 0.5
ORDER BY created DESC
LIMIT 100
See the SQL reference for complete syntax details.
Export data
Export logs, experiments, or datasets to JSON or Parquet:
import os
import requests
API_URL = "https://api.braintrust.dev/"
headers = {"Authorization": "Bearer " + os.environ["BRAINTRUST_API_KEY"]}
query = """
SELECT *
FROM project_logs('your-project-id', shape => 'traces')
WHERE created >= now() - interval '7 days'
"""
# JSON format
response = requests.post(
f"{API_URL}/btql",
headers=headers,
json={"query": query, "fmt": "json"},
).json()
# Parquet format (returns binary data)
response = requests.post(
f"{API_URL}/btql",
headers=headers,
json={"query": query, "fmt": "parquet"},
)
with open("export.parquet", "wb") as f:
f.write(response.content)
Paginate large datasets
For large datasets, paginate using cursors:
const API_URL = "https://api.braintrust.dev/";
const headers = {
Authorization: `Bearer ${process.env.BRAINTRUST_API_KEY}`,
};
async function* paginateDataset(projectName: string, datasetName: string) {
// Get dataset ID
const dsResp = await fetch(
`${API_URL}/v1/dataset?project_name=${projectName}&dataset_name=${datasetName}`,
{ headers }
);
const ds = await dsResp.json();
const datasetId = ds.objects[0].id;
let cursor = null;
while (true) {
const response = await fetch(`${API_URL}/btql`, {
method: "POST",
headers,
body: JSON.stringify({
query: {
from: {
op: "function",
name: { op: "ident", name: ["dataset"] },
args: [{ op: "literal", value: datasetId }],
},
select: [{ op: "star" }],
limit: 100,
cursor,
},
fmt: "jsonl",
}),
});
cursor =
response.headers.get("x-bt-cursor") ||
response.headers.get("x-amz-meta-bt_cursor");
const text = await response.text();
const rows = text.split("\n").filter((r) => r.trim());
if (rows.length === 0) break;
for (const row of rows) {
yield JSON.parse(row);
}
}
}
// Usage
for await (const row of paginateDataset("My Project", "My Dataset")) {
console.log(row);
}
Run experiments
Create and run experiments programmatically:
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:
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:
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
Perform operations on behalf of other users with the x-bt-impersonate-user header:
curl https://api.braintrust.dev/v1/project \
-H "Authorization: Bearer $BRAINTRUST_API_KEY" \
-H "x-bt-impersonate-user: [email protected]" \
-H "Content-Type: application/json" \
-d '{
"name": "User Project",
"org_name": "My Organization"
}'
Impersonation requires the requesting user to have Owner role over all organizations the impersonated user belongs to.
Use with Postman
Import the OpenAPI spec into Postman for interactive API exploration:
https://raw.githubusercontent.com/braintrustdata/braintrust-openapi/main/openapi/spec.json
API reference
See the complete API reference for all available endpoints, parameters, and response formats.
Next steps