> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orq.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Request metadata

> Attach app name, identity, thread ID, tags, and custom metadata to AI Gateway requests to segment cost, latency, and traces in observability.

**Use Cases**

<AccordionGroup>
  <Accordion title="Attribute requests to an app or service">
    Name each request so cost and performance slice by product, feature, or environment.
  </Accordion>

  <Accordion title="Group analytics by end user or tenant">
    Attach an **Identity** so spend, latency, and error rates attribute to a user, team, or client, with optional per-identity budgets.
  </Accordion>

  <Accordion title="Group multi-turn conversations">
    Tag each turn with a **Thread** ID so the full conversation groups together in observability.
  </Accordion>

  <Accordion title="Slice analytics by business context">
    Attach key-value metadata, such as tier, channel, or feature flag, and filter traces by those fields.
  </Accordion>
</AccordionGroup>

## Overview

Every **AI Gateway** request can carry context through several mechanisms:

* `name`: marks the app or service
* `identity`: marks the end user or tenant
* `thread`: groups a conversation
* `metadata`: carries business context
* `tags`: adds grouping labels

Each mechanism answers one question and surfaces through its own channel. Use the decision table below to pick the mechanism for a given question.

`variables` also travel with the request, but fill prompt templates instead of describing the request. The how-to for each mechanism lives in [App Tracking](/ai-gateway/app-tracking), [Identities](/ai-studio/observability/identities), and [Thread Management](/ai-gateway/thread-management); the span attribute reference is in [Metadata](/ai-studio/observability/span-attributes).

## Which mechanism to use

| Mechanism  | Answers the question                                        | Use when                                                                                        |
| ---------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| `name`     | Which app, service, or feature made this call?              | Cost and performance per product line, with a fixed set of known surfaces                       |
| `identity` | Which end user, team, or client is this request for?        | Per-user attribution, tenant billing, per-identity budgets                                      |
| `thread`   | Which conversation or workflow does this request belong to? | Multi-turn chats, multi-step agent workflows, support tickets                                   |
| `metadata` | What business context applies to this request?              | Key-value slicing by tier, channel, region, or feature flag                                     |
| `tags`     | Which labels group these requests?                          | Grouping across apps, users, or conversations, for example `support`, `premium`, `experiment-a` |

## Quick Start

Send one request with all five mechanisms attached.

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://my.orq.ai/v3/router/responses \
    -H "Authorization: Bearer $ORQ_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.4-mini",
      "input": "Refund my order",
      "name": "SupportAssistant-Production",
      "metadata": {
        "customer_tier": "premium",
        "channel": "email"
      },
      "tags": ["support", "refund"],
      "thread": {
        "id": "conversation-abc123",
        "tags": ["user-123"]
      },
      "identity": {
        "id": "user_123"
      }
    }'
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import OpenAI from "openai";

  const client = new OpenAI({
    apiKey: process.env.ORQ_API_KEY,
    baseURL: "https://my.orq.ai/v3/router",
  });

  const response = await client.responses.create({
    model: "openai/gpt-5.4-mini",
    input: "Refund my order",
    name: "SupportAssistant-Production",
    metadata: { customer_tier: "premium", channel: "email" },
    tags: ["support", "refund"],
    thread: { id: "conversation-abc123", tags: ["user-123"] },
    identity: { id: "user_123" },
  });

  console.log(response.output_text);
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  from openai import OpenAI
  import os

  client = OpenAI(
      api_key=os.environ.get("ORQ_API_KEY"),
      base_url="https://my.orq.ai/v3/router",
  )

  response = client.responses.create(
      model="openai/gpt-5.4-mini",
      input="Refund my order",
      extra_body={
          "name": "SupportAssistant-Production",
          "metadata": {"customer_tier": "premium", "channel": "email"},
          "tags": ["support", "refund"],
          "thread": {"id": "conversation-abc123", "tags": ["user-123"]},
          "identity": {"id": "user_123"},
      },
  )

  print(response.output_text)
  ```
</CodeGroup>

## Configuration

| Parameter   | Type      | Trace filter                  | Description                                                                                                                      |
| ----------- | --------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `name`      | string    | Name                          | Display name on the trace. Recommended: alphanumeric and hyphens only, under 50 characters, no timestamps or dynamic values.     |
| `metadata`  | object    | `metadata.<key>`              | Key-value pairs with string values. On the **Responses API**, non-string values are rejected with a 400.                         |
| `tags`      | string\[] | Via `orq.tags` span attribute | Labels for filtering and reporting.                                                                                              |
| `thread`    | object    | Thread ID                     | Groups related requests: `id` (required) plus optional `tags`.                                                                   |
| `identity`  | object    | Identity                      | Attributes the request to an end user: `id` (required) plus optional `display_name`, `email`, `metadata`, and `tags`.            |
| `variables` | object    | —                             | Template variables for prompt substitution. Pass secrets as `{"secret": true, "value": "..."}` so they are redacted from traces. |

<Note>
  On `/v3/router/chat/completions`:

  * `metadata` is limited to 16 key-value pairs with keys up to 64 characters and values up to 512 characters
  * `thread`, `identity`, and `tags` are passed under the `orq` object (`orq.thread`, `orq.identity`, `orq.tags`)
  * `name` is passed at the top level
</Note>

## Headers

Clients that cannot modify the request body, such as coding agents, attach metadata, identity, and thread context through headers instead. `X-ORQ-IDENTITY-ID` and `X-ORQ-THREAD-ID` are read on every AI Gateway request. `X-ORQ-METADATA-<key>` and `X-ORQ-METADATA` are read on the inference endpoints: `/v3/router/responses`, `/v3/anthropic/v1/messages`, `/v3/google/v1beta/models/*` and `/v3/google/v1beta/interactions`, and the `/v3/router/*` completions, embeddings, image, audio, moderation, OCR, and rerank endpoints.

| Header                 | Sets                                                                                       | Example                                                             |
| ---------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------- |
| `X-ORQ-METADATA-<key>` | One metadata key per header. The key is the lowercased header suffix.                      | `X-ORQ-METADATA-REPO: acme-api` sets `metadata.repo` to `acme-api`. |
| `X-ORQ-METADATA`       | Several metadata keys in one header: a comma-separated `key=value` list, or a JSON object. | `X-ORQ-METADATA: repo=acme-api,ticket=PROJ-123`                     |
| `X-ORQ-IDENTITY-ID`    | The identity ID. See [Identities](/ai-studio/observability/identities).                    | `X-ORQ-IDENTITY-ID: user_123`                                       |
| `X-ORQ-THREAD-ID`      | The thread ID.                                                                             | `X-ORQ-THREAD-ID: conversation-abc123`                              |

When the `X-ORQ-METADATA` value starts with `{`, it is parsed as a JSON object instead of the comma-separated form. String, number, and boolean values are kept; object, array, and null values are skipped.

On the Anthropic Messages and Google endpoints only, a fixed allowlist of headers (`user-agent`, `originator`, `session-id`, `session_id`, `thread-id`, `x-app`, `x-claude-code-session-id`, `x-codex-beta-features`, `anthropic-beta`, `anthropic-version`, `anthropic-dangerous-direct-browser-access`) is captured into metadata automatically, when present, to identify the calling coding assistant. No other endpoint captures these headers automatically.

<Note>
  Precedence when the same metadata key is set more than once: the body `metadata` object wins, then `X-ORQ-METADATA-<key>` headers, then the `X-ORQ-METADATA` header, then, on the Anthropic Messages and Google endpoints only, the automatically-captured allowlist above.
</Note>

**Limits**: up to 20 metadata keys per request from `X-ORQ-METADATA` and `X-ORQ-METADATA-<key>` combined. On those endpoints, the automatically-captured allowlist headers do not count against this limit. Keys must be 64 characters or fewer and match `[a-z0-9._-]+`. Values longer than 256 characters are truncated. Entries that fail these rules are dropped silently; the request still succeeds.

Header-derived metadata reaches [Traces](/ai-studio/observability/traces) as `metadata.<key>` span attributes on every endpoint listed above, filterable the same way as body metadata. It is never forwarded to the model provider.

On endpoints that take a JSON body, `X-ORQ-METADATA` and `X-ORQ-METADATA-<key>` are also available to routing rules, guardrail rules, and budgets, so a caller able to set headers on a request can influence which of those rules match. Endpoints that take multipart uploads (transcription, translation, image edit, image variation) put header metadata on traces only. The automatically-captured allowlist above never reaches rule matching, on any endpoint.

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://my.orq.ai/v3/router/responses \
    -H "Authorization: Bearer $ORQ_API_KEY" \
    -H "Content-Type: application/json" \
    -H "X-ORQ-METADATA-REPO: acme-api" \
    -H "X-ORQ-METADATA-TICKET: PROJ-123" \
    -H "X-ORQ-THREAD-ID: conversation-abc123" \
    -d '{
      "model": "openai/gpt-5.4-mini",
      "input": "Refund my order"
    }'
  ```
</CodeGroup>

## Best Practices

* **Keep app names low-cardinality**: Use a small fixed set of app names (around 50 per workspace) with consistent patterns such as `Service-Environment`. Avoid timestamps or dynamic values, which fragment analytics.
* **Use a fixed metadata key set**: Define a small set of keys (`customer_tier`, `channel`, `region`) and reuse them. High-cardinality keys, such as request IDs or timestamps, defeat filtering and increase storage.
* **Thread IDs**: Use UUIDs or composite keys such as `user-{userId}-{sessionId}` to avoid collisions across sessions.
* **Identity IDs**: Use predictable patterns such as `user-{userId}` or `tenant-{tenantId}` so identities stay consistent across requests.
* **One mechanism per question**: If the value describes the app, use `name`; if it describes the user, use `identity`; if it is business context, use `metadata`.

## What not to store in request metadata

* **PII**: Do not put emails, phone numbers, or personal data in `metadata`, `name`, or `tags`; they persist on stored traces. To keep sensitive values out of stored traces, include `"metadata"` in [`security.mask`](/ai-gateway/features/security), or enable [PII Redaction](/ai-gateway/features/plugins/pii-redaction).
* **Secrets**: Pass tokens and keys as template variables with `{"secret": true, "value": "..."}` so they are redacted from traces. See [Run Agents](/ai-studio/ai-engineering/run-agents) for the variable reference.
