Get conversation spans
Every span of one conversation, ordered by start time, with parent links so you can rebuild the tree.
GET
/
api
/
v1
/
traces
/
conversations
/
{conversation_id}
Get conversation spans
curl --request GET \
--url https://api.example.com/api/v1/traces/conversations/{conversation_id} \
--header 'X-API-KEY: <x-api-key>'import requests
url = "https://api.example.com/api/v1/traces/conversations/{conversation_id}"
headers = {"X-API-KEY": "<x-api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-KEY': '<x-api-key>'}};
fetch('https://api.example.com/api/v1/traces/conversations/{conversation_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/traces/conversations/{conversation_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-KEY: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/traces/conversations/{conversation_id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-KEY", "<x-api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/api/v1/traces/conversations/{conversation_id}")
.header("X-API-KEY", "<x-api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/traces/conversations/{conversation_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-KEY"] = '<x-api-key>'
response = http.request(request)
puts response.read_body{
"conversation_id": "<string>",
"project_id": "<string>",
"total": 123,
"spans": [
{
"timestamp": {},
"trace_id": "<string>",
"span_id": "<string>",
"parent_span_id": "<string>",
"span_name": "<string>",
"span_kind": "<string>",
"duration_ns": 123,
"duration_ms": 123,
"status_code": "<string>",
"conversation_id": "<string>",
"project_id": "<string>",
"turn_index": 123,
"function_name": "<string>",
"function_execution_id": "<string>",
"function_originating_turn_index": 123,
"function_attempt": 123,
"prompt_tokens": 123,
"cached_tokens": 123,
"prefix_cache_hit_ratio": 123
}
]
}Returns all spans recorded for a conversation. Each span carries
parent_span_id, so you can nest them: a polyai.turn contains the LLM, function and retrieval spans that produced that turn. Function spans carry span_id values you can pass to search function logs to read what that execution wrote.
Request
Headers
string
required
Account API key with read access to conversations.
Path parameters
string
required
The conversation to fetch.
Query parameters
string
The agent the conversation belongs to. Optional with an account API key.
Response
string
string
integer
Number of spans returned, at most 10,000.
object[]
Ordered by
timestamp ascending.Show properties
Show properties
datetime
Span start, UTC.
string
string
string
null on a root span. It can also name a span that is not in the response, because internal spans are filtered out; treat such spans as roots of their subtree.string
See the span names.
string
OpenTelemetry span kind, for example
Internal or Client.integer
number
string
Ok, Error or Unset.string
string
integer
0-based turn.
null on spans outside a turn.string
Function spans only.
string
Function spans only.
integer
Function spans only: the turn that triggered the call.
integer
Function spans only: attempt number, higher on retries.
integer
LLM spans, when the provider reports token usage.
integer
LLM spans, when reported: prompt tokens served from the provider’s prefix cache.
number
LLM spans, when reported: share of the prompt served from the prefix cache, 0–1.
Example
curl "https://api.us.poly.ai/api/v1/traces/conversations/CA3f2c1e9d6b7a4f8e9c0d1b2a3c4d5e6f?project_id=PROJECT-V258TF29" \
-H "X-API-KEY: YOUR_API_KEY"
{
"conversation_id": "CA3f2c1e9d6b7a4f8e9c0d1b2a3c4d5e6f",
"project_id": "PROJECT-V258TF29",
"total": 9,
"spans": [
{
"timestamp": "2026-10-27T15:07:34.930309",
"trace_id": "04f15d938151e7a09877c39978e7875f",
"span_id": "4519400991678f44",
"parent_span_id": "fb4025dc254eb11f",
"span_name": "polyai.turn",
"span_kind": "Internal",
"duration_ns": 19071851,
"duration_ms": 19.071851,
"status_code": "Unset",
"conversation_id": "CA3f2c1e9d6b7a4f8e9c0d1b2a3c4d5e6f",
"project_id": "PROJECT-V258TF29",
"turn_index": 0,
"function_name": null,
"function_execution_id": null,
"function_originating_turn_index": null,
"function_attempt": null,
"prompt_tokens": null,
"cached_tokens": null,
"prefix_cache_hit_ratio": null
}
]
}
Errors
| Status | Meaning |
|---|---|
401 | Missing or invalid API key. |
403 | The key cannot read conversations. |
404 | The conversation has no spans, or belongs to another account. |
502 | The trace backend did not answer. |
Last modified on November 10, 2026
Was this page helpful?
⌘I
Get conversation spans
curl --request GET \
--url https://api.example.com/api/v1/traces/conversations/{conversation_id} \
--header 'X-API-KEY: <x-api-key>'import requests
url = "https://api.example.com/api/v1/traces/conversations/{conversation_id}"
headers = {"X-API-KEY": "<x-api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-KEY': '<x-api-key>'}};
fetch('https://api.example.com/api/v1/traces/conversations/{conversation_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/traces/conversations/{conversation_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-KEY: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/traces/conversations/{conversation_id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-KEY", "<x-api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/api/v1/traces/conversations/{conversation_id}")
.header("X-API-KEY", "<x-api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/traces/conversations/{conversation_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-KEY"] = '<x-api-key>'
response = http.request(request)
puts response.read_body{
"conversation_id": "<string>",
"project_id": "<string>",
"total": 123,
"spans": [
{
"timestamp": {},
"trace_id": "<string>",
"span_id": "<string>",
"parent_span_id": "<string>",
"span_name": "<string>",
"span_kind": "<string>",
"duration_ns": 123,
"duration_ms": 123,
"status_code": "<string>",
"conversation_id": "<string>",
"project_id": "<string>",
"turn_index": 123,
"function_name": "<string>",
"function_execution_id": "<string>",
"function_originating_turn_index": 123,
"function_attempt": 123,
"prompt_tokens": 123,
"cached_tokens": 123,
"prefix_cache_hit_ratio": 123
}
]
}
