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

# Templates & Mapping

> Configure how Galtea formats requests to your endpoint, extracts values from responses, sets custom headers, and handles retries.

This page covers the detailed configuration for [Endpoint Connection](/concepts/product/endpoint-connection) request formatting, response extraction, and retry behavior.

## Input Template

The Input Template is a [Jinja2](https://jinja.palletsprojects.com/) template string that defines how Galtea formats the request body before sending it to your endpoint.

<Tip>
  For a detailed guide on structured input syntax (`{{ input.field_name }}`), context fields, JSON escaping, the placeholder toolbar, and missing field behavior, see the [Structured Input Template Syntax](/concepts/product/endpoint-connection-template-syntax) reference.
</Tip>

### Available Placeholders

| Placeholder                 | Description                                                                                                                                                                          |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `{{ input.<field> }}`       | Access a field from the test case input, e.g. `{{ input.user_message }}` (required)                                                                                                  |
| `{{ context.<field> }}`     | Access a field from the test case context, e.g. `{{ context.topic }}`                                                                                                                |
| `{{ session_id }}`          | The external session ID (if available)                                                                                                                                               |
| `{{ test_case_id }}`        | The test case ID                                                                                                                                                                     |
| `{{ test_id }}`             | The test ID                                                                                                                                                                          |
| `{{ galtea_session_id }}`   | The Galtea session ID                                                                                                                                                                |
| `{{ inference_result_id }}` | The inference result ID for this turn (also sent automatically as the `X-Galtea-Inference-Id` HTTP header -- useful for [trace collection](/sdk/tutorials/tracing-agent-operations)) |
| `{{ language_code }}`       | Full BCP-47 language tag of the test case, region included (e.g. `"es"` or `"es-MX"`). Empty string when no language is set.                                                         |
| `{{ language_name }}`       | English name of the test case language, with the region when the tag has one (e.g. `"Spanish"` or `"Spanish (Mexico)"`). Empty string when no language is set.                       |
| Any metadata key            | Any field stored in session metadata (e.g., `{{ sessionId }}`, `{{ tenant }}`, `{{ conversation_token }}`)                                                                           |

### Conversation History

Use `{% for turn in past_turns %}...{% endfor %}` to loop through previous conversation turns. Each turn exposes:

* `{{ turn.input }}` — Previous user input
* `{{ turn.output }}` — Previous assistant response

### Examples

**OpenAI-compatible format:**

```jinja2 theme={"system"}
{
  "model": "gpt-4",
  "messages": [
    {"role": "system", "content": "You are a helpful assistant."},
    {% for turn in past_turns %}
    {"role": "user", "content": "{{ turn.input }}"},
    {"role": "assistant", "content": "{{ turn.output }}"},
    {% endfor %}
    {"role": "user", "content": "{{ input.user_message }}"}
  ]
}
```

**Previous queries array:**

```jinja2 theme={"system"}
{
  "model": "gpt-4",
  "previous_queries": [
    {% for turn in past_turns %}
    "{{ turn.input }}"{% if not loop.last %},{% endif %}
    {% endfor %}
  ],
  "current_query": "{{ input.user_message }}"
}
```

**Custom format:**

```jinja2 theme={"system"}
{
  "data": {
    "names": ["query", "contexto"],
    "ndarray": [
      [
        "{{ input.user_message }}",
        [
          {% for turn in past_turns %}
          "{{ turn.input }}",
          "{{ turn.output }}"{% if not loop.last %},{% endif %}
          {% endfor %}
        ]
      ]
    ]
  }
}
```

<Note>
  When a loop is the **last item** in a JSON array, use `{% if not loop.last %},{% endif %}` after each iteration to prevent a trailing comma. When there's content **after** the loop (like in the OpenAI example above), trailing commas are valid and this pattern is not required.
</Note>

## Output Mapping

A JSON object defining how to extract values from the API response using [JSONPath](https://goessner.net/articles/JsonPath/) expressions.

### Special Keys

| Key                 | Behavior                                                                                                                                                                                                                                                                                                                                                                                              |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `output`            | **Required.** The AI's response content.                                                                                                                                                                                                                                                                                                                                                              |
| `session_id`        | Stored as the external session identifier, accessible via [`custom_id`](/concepts/product/version/session#session-properties).                                                                                                                                                                                                                                                                        |
| `retrieval_context` | Stored as a `RETRIEVER` trace for RAG evaluations (derived at read time, not a directly-readable field).                                                                                                                                                                                                                                                                                              |
| `traces`            | Extracts an array of [trace](/concepts/product/version/session/trace) objects and stores them linked to the inference result. Each object should contain at least a `name` field and can include any of the [Trace properties](/concepts/product/version/session/trace#trace-properties): `type`, `description`, `inputData`, `outputData`, `error`, `latencyMs`, `metadata`, `startTime`, `endTime`. |
| Any other key       | Stored in session metadata and available as `{{ key }}` in templates.                                                                                                                                                                                                                                                                                                                                 |

### JSONPath Syntax Reference

| Expression | Description                   |
| ---------- | ----------------------------- |
| `$`        | Root object                   |
| `.`        | Child operator                |
| `[]`       | Array index or child operator |
| `[*]`      | Wildcard (all elements)       |
| `[0]`      | First array element           |
| `[-1]`     | Last array element            |

### Example

```json theme={"system"}
{
  "output": "$.choices[0].message.content",
  "retrieval_context": "$.choices[0].retrieval_context",
  "session_id": "$.metadata.session_id",
  "traces": "$.metadata.traces"
}
```

### State Management

If your API returns values that need to be sent in subsequent requests (e.g., `session_id`, `tenant_id`), Galtea can automatically manage this state:

1. **Extract** — Use Output Mapping to pull values from the API response using JSONPath expressions
2. **Store** — Extracted values are saved in the session and become available as template variables
3. **Reuse** — Reference any stored value in the Input Template or URL using `{{ variable_name }}` syntax

<Tip>
  On the first turn, undefined placeholders resolve to empty strings. After the first response, all extracted values become available for subsequent turns.
</Tip>

**Example:** capture `session_id` and `tenant_id` from responses:

<CodeGroup>
  ```json Output Mapping theme={"system"}
  {
    "output": "$.text",
    "session_id": "$.session_id",
    "tenant_id": "$.tenant"
  }
  ```

  ```json Input Template theme={"system"}
  {
    "role": "user",
    "content": "{{ input.user_message }}",
    "session_id": "{{ session_id }}",
    "tenant": "{{ tenant_id }}"
  }
  ```
</CodeGroup>

## Custom Headers

Custom headers are sent with every request to your endpoint. Header values support placeholder substitution for injecting authentication credentials, so you can place tokens in any header — not just the standard `Authorization` or `X-API-Key` headers.

### Available Placeholders

| Placeholder          | Resolves to              | Available when auth type is                          |
| -------------------- | ------------------------ | ---------------------------------------------------- |
| `{{ auth_token }}`   | The authentication token | `BEARER` or `API_KEY`                                |
| `{{ api_key }}`      | The authentication token | `BEARER` or `API_KEY` (alias for `{{ auth_token }}`) |
| `{{ bearer_token }}` | The authentication token | `BEARER` or `API_KEY` (alias for `{{ auth_token }}`) |
| `{{ username }}`     | The Basic auth username  | `BASIC`                                              |
| `{{ password }}`     | The Basic auth password  | `BASIC`                                              |

Placeholders are **case-insensitive** and work with both `{{ placeholder }}` and `{ placeholder }` syntax.

### Example

```json theme={"system"}
{
  "Authorization": "Bearer {{ bearer_token }}",
  "X-Custom-Api-Key": "{{ api_key }}",
  "X-Tenant-Id": "my-tenant"
}
```

<Tip>
  If you define an `Authorization` or `X-API-Key` header in custom headers, Galtea will **not** add the default authentication header — your custom header takes precedence.
</Tip>

### W3C Trace Context Propagation

When W3C trace context propagation is enabled, Galtea adds a `traceparent` header to every request following the [W3C Trace Context](https://www.w3.org/TR/trace-context/) specification. This allows your endpoint to correlate requests with Galtea's traces without any code changes. You can add a `traceparent` key in your custom headers as a placeholder — Galtea will replace its value with the correct trace context at request time.

See [Send OpenTelemetry Traces to Galtea](/sdk/tutorials/send-opentelemetry-traces-to-galtea#how-span-content-maps-to-trace-records) for how correlated spans become Trace records.

## Timeout

How long Galtea waits for a single HTTP call to your endpoint before giving up. It is applied **per attempt**, so each retry gets the full timeout again.

<ResponseField name="Timeout" type="Number">
  Per-attempt request timeout in seconds. Default: `15`. Maximum: `120` (values above this are rejected at the API).
</ResponseField>

A timeout counts as a retryable failure. If retry is enabled, a timed-out call is retried like any other transient error.

## Rate Limit

The maximum number of requests per minute your backend can handle. Galtea throttles itself to stay under this limit, using a token bucket shared across all of Galtea, so the limit holds even when many runs execute at once.

<ResponseField name="Rate Limit" type="Number">
  Maximum requests per minute. Default: empty, which means **no limit** (no throttling). Set a number only if your backend needs Galtea to slow down.
</ResponseField>

When the limit is reached, Galtea reschedules the call for later. This wait does not use up a retry attempt and does not block other runs.

## Retry Configuration

Configure automatic retry behavior for failed requests. When enabled, Galtea retries requests that fail with a retryable HTTP status code, a timeout, or a network error. A retry wait does not block other runs: the job is rescheduled and the worker is freed while it waits.

<ResponseField name="Retry Enabled" type="Boolean">
  Whether automatic retry is enabled. Default: `true`
</ResponseField>

<ResponseField name="Max Retry Attempts" type="Number">
  Maximum number of retry attempts (`0`-`10`). Default: `1`. These are retries **after** the first call, so N attempts means up to N+1 calls to your endpoint, and **each call uses credits** (the default of 1 means up to 2 calls). `0` is only valid when retry is disabled; with retry enabled the minimum is `1`.
</ResponseField>

<ResponseField name="Initial Delay" type="Number">
  Initial delay in milliseconds before the first retry. Default: `1000` (1 second)
</ResponseField>

<ResponseField name="Backoff Strategy" type="Enum">
  Strategy for increasing delay between retry attempts:

  * `exponential` - Delay doubles with each attempt (recommended)
  * `linear` - Delay increases linearly
  * `fixed` - Constant delay between attempts

  Default: `exponential`

  The delay is always capped at **Max Delay**. With a small Max Delay, exponential and linear growth are clamped to that ceiling after the first retry, so the strategy has little effect. Raise Max Delay to let the delay grow.
</ResponseField>

<ResponseField name="Max Delay" type="Number">
  Maximum delay between retry attempts, in milliseconds. Default: `3000` (3 seconds). Capped at `60000` (60 seconds); values above this are rejected at the API.
</ResponseField>

<ResponseField name="Retryable Status Codes" type="Array of Numbers">
  HTTP status codes that should trigger a retry. Default: `[429, 500, 502, 503, 504]`. Each value must be a valid HTTP status code (`100`-`599`).

  Codes are honored literally with no client-error short-circuit. Adding a deterministic `4xx` code (such as `401`, `403`, or `422`) makes Galtea retry a call that will always fail, which wastes the full retry budget and the credits for each attempt.
</ResponseField>

## Related

<CardGroup cols={2}>
  <Card title="Structured Input Template Syntax" icon="brackets-curly" href="/concepts/product/endpoint-connection-template-syntax">
    Deep dive into `{{ input.field_name }}` and `{{ context.field_name }}` placeholder syntax, JSON escaping, and missing field behavior.
  </Card>

  <Card title="Endpoint Connection Overview" icon="plug" href="/concepts/product/endpoint-connection">
    What endpoint connections are and how to create one.
  </Card>

  <Card title="Input Schema" icon="brackets-curly" href="/concepts/product/endpoint-connection-input-schema">
    Define structured, multi-field inputs for test case generation.
  </Card>

  <Card title="Direct Inferences Tutorial" icon="play" href="/sdk/tutorials/direct-inferences-and-evaluations-from-platform">
    Run evaluations from the dashboard using your endpoint connection.
  </Card>
</CardGroup>
