Skip to main content
Version: v1.0

Query Trace Data with the Agenta API

The Agenta API lets you query trace and span data programmatically. You can filter by attributes, time ranges, and status codes. The API returns data in two formats: flat spans or hierarchical trace trees.

API Endpoints​

Two endpoints, same query body — choose the shape you want back:

POST /api/spans/query # returns flat spans
POST /api/traces/query # returns trace trees

Send queries as JSON in the request body. This approach works best for complex filters with nested conditions.

Authentication​

Include your API key in the request header:

Authorization: ApiKey YOUR_API_KEY

You can create API keys from the Settings page in your Agenta workspace.

Response Format Options​

Spans vs traces​

Spans (POST /api/spans/query): Returns individual spans in a flat list. Use this when you need span-level details.

Example response:

{
"count": 2,
"spans": [
{
"trace_id": "abc123",
"span_id": "span001",
"parent_id": "root",
"span_name": "openai.chat",
"status_code": "STATUS_CODE_OK",
"attributes": {
"ag": {
"metrics": {
"costs": { "cumulative": { "total": 0.0023 } },
"tokens": { "cumulative": { "total": 450 } }
}
}
}
},
{
"trace_id": "def456",
"span_id": "span002",
"parent_id": "root",
"span_name": "generate_response",
"status_code": "STATUS_CODE_OK",
"attributes": { "..." }
}
]
}

Traces (POST /api/traces/query): Returns complete traces as hierarchical trees. Each trace groups its spans by trace_id. Use this when you need to see the full request flow.

Example response:

{
"count": 1,
"traces": {
"abc123": {
"spans": {
"generate_response": {
"span_id": "root",
"span_name": "generate_response",
"status_code": "STATUS_CODE_OK",
"spans": {
"openai.chat": {
"span_id": "span001",
"span_name": "openai.chat",
"parent_id": "root",
"status_code": "STATUS_CODE_OK",
"attributes": {
"ag": {
"metrics": {
"costs": { "cumulative": { "total": 0.0023 } },
"tokens": { "cumulative": { "total": 450 } }
}
}
}
}
}
}
}
}
}
}

Time Windows and Limits​

Control which traces you retrieve using time ranges and result limits.

Time Range​

Specify start and end timestamps using ISO 8601 format or Unix timestamps:

{
"oldest": "2024-01-01T00:00:00Z",
"newest": "2024-01-31T23:59:59Z"
}

The oldest timestamp is included in results. The newest timestamp is excluded.

You can also use Unix timestamps (in seconds):

{
"oldest": 1704067200,
"newest": 1706745599
}

Result Limit​

Limit the number of results:

{
"limit": 100
}

Combine time ranges with limits for precise control:

{
"oldest": "2024-01-01T00:00:00Z",
"newest": "2024-01-31T23:59:59Z",
"limit": 50
}

Filtering Data​

Filter traces and spans using conditions with various operators.

Basic Filter Structure​

Each filter needs an operator and conditions:

{
"filter": {
"operator": "and",
"conditions": [
{
"field": "span_name",
"operator": "is",
"value": "my_span"
}
]
}
}

Logical Operators​

Combine conditions using these operators:

and (default): All conditions must match.

or: At least one condition must match.

not: Negates the condition.

nand: At least one condition does not match.

nor: No conditions match.

Example using OR logic:

{
"filter": {
"operator": "or",
"conditions": [
{ "field": "span_name", "value": "chat" },
{ "field": "span_name", "value": "completion" }
]
}
}

Fields You Can Filter​

Filter by these standard fields:

trace_id: Trace identifier

span_id: Span identifier

parent_id: Parent span identifier

span_name: Span name

span_kind: Type of span (SPAN_KIND_UNSPECIFIED, SPAN_KIND_INTERNAL, SPAN_KIND_SERVER, SPAN_KIND_CLIENT, SPAN_KIND_PRODUCER, SPAN_KIND_CONSUMER)

start_time: Start timestamp

end_time: End timestamp

status_code: Status code (STATUS_CODE_UNSET, STATUS_CODE_OK, STATUS_CODE_ERROR)

status_message: Status message text

attributes: Span attributes (requires key parameter)

links: Linked spans

references: References to applications, variants, or revisions

Filtering by Attributes​

Access span attributes using the key parameter:

{
"field": "attributes",
"key": "ag.type.span",
"operator": "is",
"value": "llm"
}

For nested attributes, use dot notation:

{
"field": "attributes",
"key": "ag.metrics.unit.cost",
"operator": "gt",
"value": 0.01
}

Comparison Operators​

Equality​

is (default): Exact match

is_not: Not equal

{
"field": "span_name",
"operator": "is",
"value": "openai.chat"
}

Numeric Comparisons​

eq: Equal to

neq: Not equal to

gt: Greater than

gte: Greater than or equal to

lt: Less than

lte: Less than or equal to

btwn: Between (inclusive, provide array [min, max])

gt, gte, lt, and lte can also be used for lexicographic comparisons on string values (for example span_name, status_message, or string attributes).

For datetime strings, use a consistent ISO 8601 format (for example 2024-01-15T10:30:00Z) so ordering is reliable.

Example filtering by duration:

{
"field": "attributes",
"key": "ag.metrics.unit.duration",
"operator": "gt",
"value": 1000
}

Example using between:

{
"field": "attributes",
"key": "ag.metrics.unit.duration",
"operator": "btwn",
"value": [500, 2000]
}

Example filtering a string datetime attribute:

{
"filter": {
"operator": "and",
"conditions": [
{
"field": "attributes",
"key": "tags.created_at",
"operator": "gte",
"value": "2024-01-15T00:00:00Z"
},
{
"field": "attributes",
"key": "tags.created_at",
"operator": "lt",
"value": "2024-01-20T00:00:00Z"
}
]
}
}

String Matching​

startswith: Starts with prefix

endswith: Ends with suffix

contains: Contains substring

matches: Regular expression match

like: SQL-like pattern (supports % wildcard)

Example searching span names:

{
"field": "span_name",
"operator": "contains",
"value": "api"
}

List Operations​

in: Value exists in the list

not_in: Value does not exist in the list

Example filtering multiple traces:

{
"field": "trace_id",
"operator": "in",
"value": [
"trace_id_1",
"trace_id_2",
"trace_id_3"
]
}

Existence Checks​

exists: Field or attribute exists (any value, including null)

not_exists: Field or attribute does not exist

Example checking for cost tracking:

{
"field": "attributes",
"key": "ag.metrics.unit.cost",
"operator": "exists"
}

Note: When using exists or not_exists, omit the value field.

Advanced Filtering Examples​

Multiple Conditions​

Filter production traces with slow response times:

{
"filter": {
"operator": "and",
"conditions": [
{
"field": "attributes",
"key": "environment",
"value": "production"
},
{
"field": "attributes",
"key": "ag.metrics.unit.duration",
"operator": "gt",
"value": 1000
},
{
"field": "status_code",
"operator": "is_not",
"value": "STATUS_CODE_ERROR"
}
]
}
}

Nested Logical Operators​

Find API calls that either errored or took too long:

{
"filter": {
"operator": "and",
"conditions": [
{
"field": "span_name",
"operator": "startswith",
"value": "api_"
},
{
"operator": "or",
"conditions": [
{
"field": "status_code",
"value": "STATUS_CODE_ERROR"
},
{
"field": "attributes",
"key": "ag.metrics.unit.duration",
"operator": "gt",
"value": 5000
}
]
}
]
}
}

Filter by Application References​

Find traces for specific applications:

{
"filter": {
"conditions": [
{
"field": "references",
"operator": "in",
"value": [
{ "id": "application_id_1" },
{ "id": "application_id_2" }
]
}
]
}
}

Filter by Linked Spans​

Find spans linked to specific traces:

{
"filter": {
"conditions": [
{
"field": "links",
"operator": "in",
"value": [
{
"trace_id": "trace_id_value",
"span_id": "span_id_value"
}
]
}
]
}
}

Complete Query Example​

Here's a full query that finds successful LLM calls from the last month. The same body works for both /spans/query and /traces/query:

{
"oldest": "2024-01-01T00:00:00Z",
"newest": "2024-01-31T23:59:59Z",
"limit": 50,
"filter": {
"operator": "and",
"conditions": [
{
"field": "attributes",
"key": "ag.type.span",
"value": "llm"
},
{
"field": "status_code",
"operator": "is_not",
"value": "STATUS_CODE_ERROR"
}
]
}
}

Response Structure​

POST /spans/query:

{
"count": 42,
"spans": [...]
}

POST /traces/query:

{
"count": 7,
"traces": [...]
}

count: Number of results returned. spans: Array of spans. traces: Array of trace trees.

Span Format​

Each span contains:

{
"trace_id": "...",
"span_id": "...",
"parent_id": "...",
"span_name": "openai.chat",
"span_kind": "SPAN_KIND_CLIENT",
"start_time": "2024-01-15T10:30:00Z",
"end_time": "2024-01-15T10:30:03Z",
"status_code": "STATUS_CODE_OK",
"attributes": {
"ag": {
"data": {
"inputs": {...},
"outputs": {...}
},
"metrics": {
"costs": {...},
"tokens": {...},
"duration": {...}
},
"type": {
"span": "llm"
}
}
}
}

Trace Format​

Each trace organizes spans hierarchically by name:

{
"trace_id_1": {
"spans": {
"root_span": {
"span_id": "...",
"spans": {
"child_span": {
"span_id": "...",
"..."
}
}
}
}
}
}

Error Responses​

The API returns standard HTTP status codes:

200 OK: Query succeeded

400 Bad Request: Invalid filter syntax or parameters

401 Unauthorized: Missing or invalid API key

422 Unprocessable Entity: Validation errors in the request

Python Example​

Here's a complete example using Python:

import requests
from datetime import datetime, timedelta, timezone

AGENTA_HOST = "https://cloud.agenta.ai"
API_KEY = "your_api_key_here"

# Query spans from the last 7 days
now = datetime.now(timezone.utc)
week_ago = now - timedelta(days=7)

query = {
"oldest": week_ago.isoformat(),
"newest": now.isoformat(),
"limit": 100,
"filter": {
"operator": "and",
"conditions": [
{
"field": "attributes",
"key": "ag.type.span",
"value": "llm"
},
{
"field": "status_code",
"value": "STATUS_CODE_OK"
}
]
}
}

response = requests.post(
f"{AGENTA_HOST}/api/spans/query",
headers={
"Authorization": f"ApiKey {API_KEY}",
"Content-Type": "application/json"
},
json=query
)

data = response.json()
print(f"Found {data['count']} spans")

JavaScript Example​

Here's the same query in JavaScript:

const AGENTA_HOST = "https://cloud.agenta.ai";
const API_KEY = "your_api_key_here";

// Query spans from the last 7 days
const now = new Date();
const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);

const query = {
oldest: weekAgo.toISOString(),
newest: now.toISOString(),
limit: 100,
filter: {
operator: "and",
conditions: [
{
field: "attributes",
key: "ag.type.span",
value: "llm"
},
{
field: "status_code",
value: "STATUS_CODE_OK"
}
]
}
};

const response = await fetch(
`${AGENTA_HOST}/api/spans/query`,
{
method: "POST",
headers: {
"Authorization": `ApiKey ${API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify(query)
}
);

const data = await response.json();
console.log(`Found ${data.count} spans`);

Next Steps​

Learn about the Analytics Data API for aggregated metrics and time-series data.

Explore the API Reference for complete endpoint documentation.

Check out Filtering in the UI to learn about the visual query builder.