요청 헤더

게이트웨이가 인식하는 선택적 헤더 3개: 두 개는 자체 트레이스 컨텍스트를 당사 로그까지 전달하고, 하나는 같은 대화를 동일한 업스트림에 고정해 prompt caching이 계속 적중하게 합니다. 보내지 않아도 동작은 달라지지 않습니다.

헤더 게이트웨이 동작 용도
X-Trace-Id 응답으로 되돌아오고 호출에 기록되어, 같은 트레이스의 다른 호출과 함께 묶입니다. 호출을 자체 트레이싱 시스템과 연결.
X-Span-Id 응답으로 되돌아오고 호출에 기록되며, 트레이스 워터폴에서 그 호출의 이름이 됩니다. 해당 트레이스 내 하나의 span을 식별.
X-Session-Id 응답으로 되돌아오고 호출에 기록됩니다. 같은 값을 가진 연속 요청은 동일한 채널과 동일한 업스트림 키에 고정됩니다. 대화 전반에서 prompt caching을 계속 활용.
X-Request-ID 클라이언트 값을 신뢰하지 않습니다. 보낸 값은 X-Client-Request-ID로 반환되며, 응답의 X-Request-ID는 항상 게이트웨이가 생성한 UUIDv7입니다. 게이트웨이 측 호출 식별자입니다. 문의 시 이 값을 알려주세요.

보내는 방법

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"}]
  }'

다른 도구가 이미 보내는 헤더

호출에 저희 헤더 3개가 없으면, 게이트웨이는 코딩 에이전트, SDK, 트레이싱 표준이 이미 보내는 해당 헤더를 읽습니다. 그래서 이런 실행도 아무것도 바꾸지 않고 트레이스에서 묶입니다.

헤더 읽는 방식 보내는 쪽
X-Claude-Code-Session-Id 세션 Claude Code
X-Litellm-Session-Id 세션 LiteLLM SDK, OpenHands
Session-Id 세션 OpenAI Codex CLI
Helicone-Session-Id 세션 Helicone
X-OpenWebUI-Chat-Id 세션 Open WebUI
X-Opencode-Session-Id 세션 OpenCode
baggage: session.id=… 세션 W3C Baggage (OpenTelemetry)
baggage: gen_ai.conversation.id=… 세션 W3C Baggage (OpenTelemetry)
baggage: langfuse_session_id=… 세션 Langfuse SDK
X-Session-Affinity 세션 OpenClaw, OpenCode, Kilo Code
X-Litellm-Trace-Id 트레이스 LiteLLM SDK
X-Portkey-Trace-Id 트레이스 Portkey
traceparent 트레이스(parent id를 스팬으로 읽음) W3C Trace Context (OpenTelemetry)
X-Claude-Code-Prompt-Id 트레이스 Claude Code
X-Interaction-Id 트레이스 GitHub Copilot
X-Codex-Turn-Metadata 트레이스 OpenAI Codex CLI
baggage: langfuse_trace_id=… 트레이스 Langfuse SDK
X-Portkey-Span-Id 스팬 Portkey
X-OpenWebUI-User-Id 최종 사용자(_user 라벨) Open WebUI
baggage: user.id=… 최종 사용자(_user 라벨) W3C Baggage (OpenTelemetry)
baggage: langfuse_user_id=… 최종 사용자(_user 라벨) Langfuse SDK

둘 다 있으면 항상 저희 헤더가 우선합니다. Session-Id와 X-Codex-Turn-Metadata는 Codex CLI에서, X-Interaction-Id는 GitHub Copilot에서 온 요청에서만 읽으며 User-Agent로 구분합니다. 트레이스 ID가 전혀 없는 호출에는 게이트웨이의 요청 ID가 X-Trace-Id로 반환됩니다.

/v1/chat/completions와 /v1/responses에서는 세션 ID를 본문의 session_id로 보낼 수도 있습니다(OpenAI SDK에서는 extra_body에 넣습니다). 헤더가 있으면 헤더가 우선하며, 이 필드는 프로바이더로 보내기 전에 제거됩니다.

OpenClaw는 모델 호출마다 traceparent를 보내므로 별도 설정 없이 실행이 트레이스로 묶입니다. 세션으로 묶으려면 모델의 compat.sendSessionAffinityHeaders를 켜세요. Open WebUI는 ENABLE_FORWARD_USER_INFO_HEADERS를 켜면 채팅 ID와 사용자 ID를 보냅니다. 함께 오는 이름과 이메일 헤더는 읽지 않습니다. 이런 정보를 보내지 않는 에이전트(Cursor, Aider, Cline, Continue 및 대부분의 에이전트 프레임워크)는 커스텀 헤더에 X-Session-Id를 추가해야 합니다.

W3C Trace Context와 Baggage

traceparent에서 트레이스를, 그 parent id에서 스팬을 읽습니다. OpenTelemetry HTTP 자동 계측을 켜면 자동으로 붙습니다. 나머지는 baggage에 OpenTelemetry 이름 그대로 넣습니다. 세션은 session.id 또는 gen_ai.conversation.id, 에이전트는 gen_ai.agent.id와 gen_ai.agent.name, 최종 사용자는 user.id입니다. 이 값들은 애플리케이션 코드에서 직접 baggage에 넣어야 합니다. OpenTelemetry SDK는 스팬 속성을 baggage로 복사하지 않습니다. 에이전트 이름은 에이전트 유형으로 저장되며 영문자, 숫자, ., _, -만 허용됩니다. tracestate는 읽지 않습니다.

세션 안의 에이전트

서브 에이전트를 시작하는 코딩 에이전트는 각 호출이 어느 에이전트의 것인지 알려 줍니다. 게이트웨이는 이를 호출과 함께 저장하므로, 세션에서는 에이전트별 비용을, 트레이스에서는 어떤 호출이 압축이나 보조 호출이었는지와 두 호출 사이에 어떤 도구가 실행됐는지를 볼 수 있습니다. 이 헤더들은 라우팅을 바꾸지 않습니다. 서브 에이전트는 세션과 같은 업스트림에 머뭅니다.

헤더 읽는 방식 보내는 쪽
X-Agent-Id 에이전트 Synthorai
X-Parent-Agent-Id 이를 시작한 에이전트 또는 세션 Synthorai
X-Claude-Code-Agent-Id 에이전트 Claude Code
X-Claude-Code-Parent-Agent-Id 이를 시작한 에이전트 또는 세션 Claude Code
Thread-Id 에이전트 OpenAI Codex CLI
X-Codex-Parent-Thread-Id 이를 시작한 에이전트 또는 세션 OpenAI Codex CLI
baggage: gen_ai.agent.id=… 에이전트 W3C Baggage (OpenTelemetry)
X-Parent-Session-Id 이를 시작한 에이전트 또는 세션 OpenCode, Kilo Code
X-Opencode-Parent-Session-Id 이를 시작한 에이전트 또는 세션 OpenCode
X-Claude-Code-Request-Class 호출의 종류 Claude Code
X-Claude-Code-Agent-Type 호출의 종류 Claude Code
X-Claude-Code-Compaction 호출의 종류 Claude Code
X-Claude-Code-Context-Compacted 호출의 종류 Claude Code
X-Openai-Subagent 호출의 종류 OpenAI Codex CLI
baggage: gen_ai.agent.name=… 호출의 종류 W3C Baggage (OpenTelemetry)
X-Claude-Code-Prev-Tool-Durations 도구 실행 시간 Claude Code

Claude Code는 에이전트 ID를 기본으로 보냅니다. 호출의 종류와 도구 실행 시간은 실행 환경에 CLAUDE_CODE_GATEWAY_HINT_HEADERS=1을 설정했을 때만 보냅니다.

저장하는 것: 이 ID들, 에이전트의 유형, 호출의 종류, 도구 이름과 밀리초 단위 실행 시간. 저장하지 않는 것: 에이전트에 붙인 이름, 도구가 읽거나 쓴 내용.

요청에 라벨 붙이기

X-Synthorai-Metadata에 값이 모두 문자열인 JSON 객체를 넣어 이 요청이 무엇을 위한 것인지(기능, 환경, 어느 사용자인지) 알려 주세요. 라벨은 로그의 요청 상세에 표시되고, 로그·트레이스·세션을 필터링하는 데 쓰이며(metadata.feature = checkout), Analytics의 Breakdown에서 라벨별로 합산되고, 내보내기에도 함께 나갑니다.

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"}]}'

라벨은 최대 10개입니다. 키는 a-z 0-9 _ . - 1~32자, 값은 128바이트 이하의 문자열입니다. _user는 이 요청이 어느 최종 사용자를 위한 것인지를 나타내며, 밑줄로 시작하는 다른 키는 예약되어 있습니다. 규칙에 맞지 않는 라벨은 버려지고 요청은 그대로 실행됩니다. 버려진 키는 응답의 X-Synthorai-Metadata-Dropped에 표시됩니다.

라벨은 요청 로그와 같은 기간 동안 요청과 함께 보관되며, 라벨로 필터링할 수 있는 범위는 최근 90일입니다. 프롬프트 내용, 개인 정보, 비밀 값은 넣지 마세요. 자격 증명처럼 보이는 값은 [redacted]로 저장됩니다. 라벨은 프로바이더에 전송되지 않습니다.

세션 어피니티

캐시 항목은 공급사 측 하나의 API 키에 묶입니다. 한 채널이 여러 키를 가질 수 있고, 힌트가 없으면 게이트웨이는 호출을 분산시킵니다. 그래서 대화의 두 번째 턴이 접두사를 본 적 없는 키에 도달해 쓰기 비용을 다시 지불하게 됩니다.

한 대화의 모든 호출에 같은 값을 보내고, 다른 대화에는 다른 값을 사용하세요. 서버에는 아무것도 저장되지 않고 만료도 없습니다. 값을 해시해 채널과 키를 고르므로 같은 값은 항상 같은 곳으로 해석됩니다.

/v1/chat/completions와 /v1/responses 두 OpenAI 호환 엔드포인트에서는 헤더를 생략해도 됩니다. 요청 본문에 prompt_cache_key가 있으면 게이트웨이가 이를 어피니티 키로 사용합니다. /v1/messages와 Gemini 엔드포인트에서는 헤더를 보내세요.

어피니티는 best-effort입니다. 우선순위가 같은 후보 중 어느 것을 고를지만 결정하며, 장애 조치·레이트 리밋 쿨다운·재시도·명시적 라우팅 설정이 모두 우선합니다. 모델의 정가는 저희가 선택할 수 있는 어느 채널에서나 동일합니다.

제한

  • 각 128바이트. 초과분은 잘립니다. 제어 문자나 출력 가능한 ASCII 범위를 벗어난 값이 포함되면 전체가 폐기되어 반환도 기록도 되지 않습니다. 이 값들은 응답 헤더와 로그 줄에 들어가므로 헤더·로그 인젝션을 막습니다.
  • 게이트웨이에서 멈춥니다. 세 헤더 모두 모델 공급사로 전달되지 않습니다. 아웃바운드 요청은 인증, 콘텐츠 타입, 공급사 전용 헤더만 담습니다.
  • 어느 것도 과금 식별자가 아닙니다. 과금, 중복 제거, 대사는 모두 게이트웨이 자체 X-Request-ID를 기준으로 하며 클라이언트가 제어하는 값은 쓰지 않습니다.

문제가 생겼을 때

  • 보낸 X-Trace-Id 또는 응답의 X-Request-ID를 알려주세요. 둘 중 하나면 해당 호출을 찾을 수 있습니다.
  • 트레이스 ID는 로그와 트레이스의 해당 호출에 표시되므로, 문의하기 전에 직접 찾아볼 수 있습니다.
  • 어피니티가 동작하는지 확인하려면 같은 X-Session-Id로 동일한 긴 프리픽스를 여러 번 보내고 로그의 캐시 열을 보세요. 첫 호출은 캐시 쓰기, 이후 호출은 읽기여야 합니다. 값을 바꾸면 쓰기가 다시 나타납니다.

함께 보기: Prompt Caching(프롬프트 캐싱) · 트레이스와 세션