---
title: "Threads and traces"
subtitle: "Group a conversation's turns into a thread, and see every step of a request as one trace."
---

Every gateway request is one trace, with a row for each model call it makes. A thread groups the requests of one conversation, turn after turn. You control both with a few Respan params, and you can join gateway calls to the traces your own code already writes.

<Tabs>
<Tab title="cURL">
```bash
curl -i https://gateway.respan.ai/v1/chat/completions \
  -H "Authorization: Bearer $RESPAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.5",
    "messages": [{"role": "user", "content": "Where is my order?"}],
    "thread_identifier": "conv_5d21",
    "trace_unique_id": "order-help-7f3a",
    "span_name": "support-reply"
  }'
```
</Tab>
<Tab title="Python">
```python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://gateway.respan.ai/v1",
    api_key=os.environ["RESPAN_API_KEY"],
)

raw = client.chat.completions.with_raw_response.create(
    model="gpt-5.5",
    messages=[{"role": "user", "content": "Where is my order?"}],
    extra_body={
        "thread_identifier": "conv_5d21",
        "trace_unique_id": "order-help-7f3a",
        "span_name": "support-reply",
    },
)
print(raw.headers.get("x-respan-log-id"))
response = raw.parse()
```
</Tab>
<Tab title="TypeScript">
```typescript
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://gateway.respan.ai/v1",
  apiKey: process.env.RESPAN_API_KEY,
});

const { data, response } = await client.chat.completions
  .create({
    model: "gpt-5.5",
    messages: [{ role: "user", content: "Where is my order?" }],
    // @ts-expect-error Respan parameters
    thread_identifier: "conv_5d21",
    trace_unique_id: "order-help-7f3a",
    span_name: "support-reply",
  })
  .withResponse();
console.log(response.headers.get("x-respan-log-id"));
```
</Tab>
</Tabs>

## Parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| [`thread_identifier`](#threads) | string | None | The conversation the request belongs to. |
| [`trace_unique_id`](#trace-id) | string | The request's `X-Respan-Gateway-Request-Id` | The trace to put the request's rows in. |
| [`span_name`](#root-row-name) | string | The call's own name | The name of the request's root row. Cut to 255 characters. |
| [`trace_name`](#root-row-name) | string | None | The trace's name, used for the root row when `span_name` is not set. |

Send them at the top level, in `respan_params`, or in the `X-Data-Respan-Params` header, like any [Respan param](/docs/ai-gateway/customers/respan-params).

## Threads

Send the same `thread_identifier` on every turn of a conversation. Chat Completions doesn't keep history for you, so still send the full conversation in `messages` each turn; the thread is how Respan groups the turns afterwards.

In **Gateway** › **Logs**, group by **Threads** to see each conversation as one item with its turns in order, or filter by **Thread ID**.

## One trace per request

The gateway writes one row for each call it makes, and the rows of one request form a trace:

| Row | What it is | Parent |
|---|---|---|
| **Root** | The request's first model call. `X-Respan-Log-Id` names it. | None |
| **Model call** | Each later model call of the request | The root |

Rows are typed by what they are: `chat`, `embedding`, `image`, `speech`, `transcription`, or `video`.

Every row of a request carries the same `X-Respan-Gateway-Request-Id`. The root row is published as soon as its call ends; the other rows when the request ends. Once every row of the trace is in, Respan fires the `trace_completed` [webhook](/docs/documentation/admin/webhooks) event.

### Trace ID

Without `trace_unique_id`, the trace ID is the request's `X-Respan-Gateway-Request-Id`, so each request is its own trace. Send the same `trace_unique_id` on several requests to put them all in one trace, for example every model call of one agent run.

### Root row name

The root row is named by `span_name`. Without it, the gateway uses `trace_name`, then the call's own name. Name the root after what the request does in your app, such as `support-reply` or `classify-ticket`, so traces are easy to tell apart.

## What you see

**In the response.** Every answer carries two headers, set before any provider is called, so streamed and refused requests have them too:

| Header | What it names |
|---|---|
| `X-Respan-Log-Id` | The request's root row. Paste it into the Logs search to open the call. |
| `X-Respan-Gateway-Request-Id` | The whole request. Every row it writes carries it. |

**In Logs.** Open **Gateway** › **Logs**, paste the `X-Respan-Log-Id`, and open the request. Group by **Traces** to see the root with its model calls and tool calls as a tree, with each row's latency, tokens, and cost. See [Inspect spans and traces](/docs/documentation/features/observe/view-debug-traces).

**On your bill.** Each model call row is charged like any call. The trace's total is the sum of its rows.

## Link calls from your own tracing

If your app is traced with the [Respan SDK](/docs/documentation/features/tracing/quickstart) or OpenTelemetry, you can put a gateway request in your app's trace. Send your trace's ID as `trace_unique_id`:

```python
from opentelemetry import trace

ctx = trace.get_current_span().get_span_context()

response = client.chat.completions.create(
    model="gpt-5.5",
    messages=[{"role": "user", "content": "Summarize this ticket."}],
    extra_body={
        "trace_unique_id": format(ctx.trace_id, "032x"),
        "span_name": "summarize-ticket",
    },
)
```

The gateway's rows join your trace, so one trace shows your code, the gateway call, and every step inside it.

{/* REVIEW: span_parent_id and span_unique_id (nest the root row under a span of your own) were removed because they are not in the confirmed gateway-next param list; the row code still lists them. Also confirm the trace ID format the Respan SDK writes (OTel hex as above) so gateway rows join SDK traces. */}

## Next steps

- [Respan params](/docs/ai-gateway/customers/respan-params)
- [Logs](/docs/ai-gateway/observability/logs-and-traces)
- [Custom IDs & attributes](/docs/documentation/features/observe/custom-ids)
