요청 헤더
게이트웨이가 인식하는 선택적 헤더 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(프롬프트 캐싱) · 트레이스와 세션