Cabeçalhos de requisição

Três cabeçalhos opcionais que o gateway entende: dois levam o seu contexto de rastreamento até os nossos logs e um mantém uma conversa no mesmo upstream para que o cache de prompts continue acertando. Não enviar nenhum deles não muda nada.

Cabeçalho O que o gateway faz Para que serve
X-Trace-Id Devolvido na resposta e gravado na chamada, o que a agrupa com as demais chamadas do trace. Ligar uma chamada ao seu próprio sistema de tracing.
X-Span-Id Devolvido na resposta e gravado na chamada; dá nome à chamada na cascata do trace. Identificar um span dentro desse rastreamento.
X-Session-Id Devolvido e gravado na chamada. Requisições consecutivas com o mesmo valor ficam fixas ao mesmo canal e à mesma chave de upstream. Manter o cache de prompts quente ao longo de uma conversa.
X-Request-ID Não é aceite o seu valor. Ele volta como X-Client-Request-ID; o X-Request-ID da resposta é sempre o UUIDv7 gerado pelo gateway. A identidade da chamada no gateway - cite-a em um chamado de suporte.

Como enviá-los

curl https://synthorai.io/v1/chat/completions \
  -H "Authorization: Bearer $SYNTHORAI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-Session-Id: conv-8f3a2b" \
  -H "X-Trace-Id: 7c1d9e40f2b84a17" \
  -H "X-Span-Id: 2f9b41c8" \
  -d '{
    "model": "claude-sonnet-5",
    "messages": [{"role": "user", "content": "Hello"}]
  }'

Cabeçalhos que outras ferramentas já enviam

Quando uma chamada não traz nenhum dos nossos três cabeçalhos, o gateway lê o cabeçalho equivalente que um agente de código, um SDK ou um padrão de rastreamento já envia, e essas execuções são agrupadas em Traces sem nenhuma mudança do seu lado.

Cabeçalho Lido como Enviado por
X-Claude-Code-Session-Id Sessão Claude Code
X-Litellm-Session-Id Sessão LiteLLM SDK, OpenHands
Session-Id Sessão OpenAI Codex CLI
Helicone-Session-Id Sessão Helicone
X-OpenWebUI-Chat-Id Sessão Open WebUI
X-Opencode-Session-Id Sessão OpenCode
baggage: session.id=… Sessão W3C Baggage (OpenTelemetry)
baggage: gen_ai.conversation.id=… Sessão W3C Baggage (OpenTelemetry)
baggage: langfuse_session_id=… Sessão Langfuse SDK
X-Session-Affinity Sessão OpenClaw, OpenCode, Kilo Code
X-Litellm-Trace-Id Trace LiteLLM SDK
X-Portkey-Trace-Id Trace Portkey
traceparent Trace; o parent id vira o span W3C Trace Context (OpenTelemetry)
X-Claude-Code-Prompt-Id Trace Claude Code
X-Interaction-Id Trace GitHub Copilot
X-Codex-Turn-Metadata Trace OpenAI Codex CLI
baggage: langfuse_trace_id=… Trace Langfuse SDK
X-Portkey-Span-Id Span Portkey
X-OpenWebUI-User-Id Usuário final (rótulo _user) Open WebUI
baggage: user.id=… Usuário final (rótulo _user) W3C Baggage (OpenTelemetry)
baggage: langfuse_user_id=… Usuário final (rótulo _user) Langfuse SDK

Quando os dois estão presentes, o nosso cabeçalho sempre vence. Session-Id e X-Codex-Turn-Metadata só são lidos da CLI do Codex, e X-Interaction-Id só do GitHub Copilot, reconhecidos pelo User-Agent. Uma chamada sem nenhum ID de trace recebe o ID de requisição do gateway como X-Trace-Id.

Em /v1/chat/completions e /v1/responses, o id da sessão também pode ir no corpo, como session_id (com o SDK da OpenAI, em extra_body). Um cabeçalho tem prioridade, e o campo é removido antes de a requisição ir para o provedor.

O OpenClaw envia traceparent em cada chamada de modelo, então suas execuções são agrupadas em traces sem configuração; para sessões, ative compat.sendSessionAffinityHeaders no modelo. O Open WebUI envia o id do chat e o do usuário quando ENABLE_FORWARD_USER_INFO_HEADERS está ativo; os cabeçalhos de nome e e-mail que vêm junto não são lidos. Um agente que não envia nada disso (Cursor, Aider, Cline, Continue e a maioria dos frameworks de agentes) precisa de X-Session-Id nos cabeçalhos personalizados.

W3C Trace Context e Baggage

traceparent fornece o trace e, pelo parent id, o span; uma instrumentação HTTP do OpenTelemetry o adiciona sozinha. O restante vai em baggage, com os nomes do OpenTelemetry: session.id ou gen_ai.conversation.id para a sessão, gen_ai.agent.id e gen_ai.agent.name para o agente, user.id para o usuário final. Seu código precisa colocá-los lá: um SDK do OpenTelemetry não copia atributos de span para o baggage. O nome de um agente é guardado como o tipo dele e aceita letras, dígitos, ., _ e -. tracestate não é lido.

Agentes dentro de uma sessão

Um agente de código que inicia subagentes informa qual agente fez cada chamada. O gateway guarda isso junto com a chamada: assim, uma sessão mostra o custo por agente, e um trace mostra quais chamadas foram compactações ou chamadas auxiliares e quais ferramentas rodaram entre duas chamadas. Nenhum desses cabeçalhos muda o roteamento: um subagente continua no upstream da sua sessão.

Cabeçalho Lido como Enviado por
X-Agent-Id Agente Synthorai
X-Parent-Agent-Id O agente ou a sessão que o iniciou Synthorai
X-Claude-Code-Agent-Id Agente Claude Code
X-Claude-Code-Parent-Agent-Id O agente ou a sessão que o iniciou Claude Code
Thread-Id Agente OpenAI Codex CLI
X-Codex-Parent-Thread-Id O agente ou a sessão que o iniciou OpenAI Codex CLI
baggage: gen_ai.agent.id=… Agente W3C Baggage (OpenTelemetry)
X-Parent-Session-Id O agente ou a sessão que o iniciou OpenCode, Kilo Code
X-Opencode-Parent-Session-Id O agente ou a sessão que o iniciou OpenCode
X-Claude-Code-Request-Class Tipo de chamada Claude Code
X-Claude-Code-Agent-Type Tipo de chamada Claude Code
X-Claude-Code-Compaction Tipo de chamada Claude Code
X-Claude-Code-Context-Compacted Tipo de chamada Claude Code
X-Openai-Subagent Tipo de chamada OpenAI Codex CLI
baggage: gen_ai.agent.name=… Tipo de chamada W3C Baggage (OpenTelemetry)
X-Claude-Code-Prev-Tool-Durations Tempos de execução das ferramentas Claude Code

O Claude Code envia os ids de agente por padrão. O tipo de chamada e os tempos de execução das ferramentas só são enviados se CLAUDE_CODE_GATEWAY_HINT_HEADERS=1 estiver definido onde ele roda.

Guardado: os ids, o tipo de um agente, o tipo de chamada e os nomes das ferramentas com seus tempos de execução em milissegundos. Não guardado: o nome que você deu a um agente e tudo o que uma ferramenta leu ou escreveu.

Rotular uma requisição

Envie X-Synthorai-Metadata com um objeto JSON de strings para dizer para que serviu uma requisição: uma funcionalidade, um ambiente, um dos seus usuários. Os rótulos aparecem na requisição nos logs, filtram logs, traces e sessões (metadata.feature = checkout), são somados em Analytics, Breakdown, e saem com as suas exportações.

curl https://synthorai.io/v1/chat/completions \
  -H "Authorization: Bearer $SYNTHORAI_API_KEY" \
  -H 'X-Synthorai-Metadata: {"feature":"checkout","env":"prod","_user":"u_123"}' \
  -d '{"model":"claude-sonnet-5","messages":[{"role":"user","content":"Hi"}]}'

Até 10 rótulos. Uma chave tem de 1 a 32 caracteres de a-z 0-9 _ . -; um valor é uma string de até 128 bytes. _user indica o usuário final para quem a requisição foi feita; qualquer outra chave que comece com sublinhado é reservada. Um rótulo que quebra uma regra é descartado e a requisição roda mesmo assim: a resposta informa as chaves descartadas em X-Synthorai-Metadata-Dropped.

Os rótulos são mantidos com a requisição pelo mesmo tempo que o registro de requisições, e o filtro por rótulo cobre os últimos 90 dias. Não coloque neles texto de prompts, dados pessoais nem segredos; um valor que parece uma credencial é armazenado como [redacted]. Eles nunca são enviados ao provedor.

Afinidade de sessão

Uma entrada de cache vive numa única chave de API no provedor. Um canal pode ter várias chaves e, sem uma pista, o gateway distribui as chamadas por elas: o segundo turno de uma conversa pode cair numa chave que nunca viu o seu prefixo e pagar de novo o custo de escrita.

Envie o mesmo valor em cada chamada de uma conversa e um valor diferente para outra conversa. Nada é guardado no servidor e nada expira: o valor passa por hash para escolher canal e chave, por isso o mesmo valor sempre resolve da mesma forma.

Nos dois endpoints compatíveis com OpenAI - /v1/chat/completions e /v1/responses - você pode omitir o cabeçalho: se o corpo da requisição tiver prompt_cache_key, o gateway o usa como chave de afinidade. Em /v1/messages e nos endpoints do Gemini, envie o cabeçalho.

A afinidade é best effort: apenas decide qual canal é escolhido entre candidatos igualmente preferidos. Failover, resfriamento por limite de taxa, novas tentativas e uma preferência de roteamento explícita sempre têm prioridade. O preço de tabela de um modelo é o mesmo em qualquer canal que possamos escolher.

Limites

  • 128 bytes cada. Valores maiores são truncados. Um valor com caracteres de controle ou fora do ASCII imprimível é descartado por completo: não é devolvido nem registrado. Esses valores acabam em um cabeçalho de resposta e em uma linha de log, o que impede injeção de cabeçalhos e de logs.
  • Param no gateway. Nenhum dos três é encaminhado para o provedor do modelo: a requisição de saída leva apenas autenticação, tipo de conteúdo e cabeçalhos próprios do provedor.
  • Nenhum identifica uma chamada para cobrança. Cobrança, desduplicação e reconciliação se baseiam no X-Request-ID do próprio gateway, nunca em um valor que você controle.

Quando algo corre mal

  • Indique o X-Trace-Id que enviou ou o X-Request-ID da resposta: qualquer um permite-nos encontrar a chamada exata.
  • O seu ID de trace aparece na chamada em Logs e em Traces, então você pode encontrá-la antes de abrir um chamado.
  • Para confirmar que a afinidade funciona, envie o mesmo prefixo longo algumas vezes com um único X-Session-Id e observe as colunas de cache em Logs: a primeira chamada grava no cache e as seguintes devem ler dele. Mude o valor e a gravação deve reaparecer.

Ver também: Prompt Caching · Traces e sessões