# Advanced HTTP tools

Shape the request and response of an `http` handler with `httpConfig` fields, so an existing HTTP API becomes a clean tool without a wrapper service. The dashboard does not expose these fields; set them in the ToolRegistry YAML.

## Prerequisites

- A ToolRegistry with an `http` handler and a `tool.inputSchema`. See the [ToolRegistry reference](/reference/core/toolregistry/#http-handler).
- The tool listed in `tools` on the PromptPack prompt that should use it. The runtime offers the model only the tools a prompt declares.

Each snippet below is a fragment of one handler's `httpConfig`.

## Put arguments in the URL path

Set `urlTemplate` to a full URL, including scheme and host. It replaces `endpoint`, and `{argName}` placeholders are filled with the argument's value, escaped for where the placeholder sits: path-escaped before the `?`, query-escaped after it. An argument containing `/` or `?` stays inside its own path segment, so a model cannot steer the request to another endpoint. Go template syntax such as `{{.argName}}` does not work.

```yaml
httpConfig:
  endpoint: https://api.example.com          # ignored when urlTemplate is set
  method: GET
  urlTemplate: "https://api.example.com/users/{user_id}/orders/{order_id}"
```

A relative path fails when the request is sent. Each argument used in the template is removed from the body and query. Argument names come from the tool's `inputSchema`.

## Send arguments as query parameters or headers

Arguments go into the JSON body for POST, PUT and PATCH, and into the query string for GET, DELETE and other methods. To redirect specific arguments:

```yaml
httpConfig:
  endpoint: https://api.example.com/search
  method: GET
  queryParams: [query, limit]        # these arguments become URL query parameters
  headerParams:
    customer_id: X-Customer-ID       # argument name -> header name; value sent as-is
```

Both fields remove the arguments they use from the request body. A GET or DELETE has no body, so its other arguments stay in the query string alongside the listed ones.

## Add fixed values the model never sees

`staticQuery` and `staticBody` add values to every request. They are not part of the tool schema, so the model cannot see them.

```yaml
httpConfig:
  endpoint: https://api.example.com/v1/search
  method: POST
  staticQuery:
    api_version: "2024-01"
  staticBody:
    source: omnia
    include_metadata: true
```

`staticBody` applies to POST, PUT and PATCH only, and an argument with the same name overrides a static field. Use these fields for non-secret constants. For credentials, use the [auth stanza](/how-to/tools/authenticate-tools/) so the value stays out of the tools ConfigMap.

## Source a secret header

`httpConfig.headers` values are stored in plaintext in the ToolRegistry, so use them only for non-secret headers. For a secret header, such as a second API key or a signing token, map the header name to a Secret key with `headersFromSecret`:

```yaml
httpConfig:
  endpoint: https://api.example.com/v1/things
  method: POST
  headersFromSecret:
    X-Api-Signature:
      name: my-tool-credentials   # a Secret in the same namespace
      key: SIGNING_TOKEN
```

The operator copies each referenced value into the `<agentruntime>-tool-secrets` Secret and mounts it read-only into the runtime. The runtime reads the value on every call, so a rotated Secret takes effect without a redeploy, and the value never enters the tools ConfigMap.

Do not use `headersFromSecret` for a header the auth stanza owns: `Authorization`, or the custom `auth.workloadIdentity.header`. The AgentRuntime reconcile rejects that. A secret header overrides a `headers` entry of the same name.

## Reshape the request and response

`bodyMapping` is a JMESPath expression applied to the outgoing body. `responseMapping` is applied to the response before it reaches the model, so a smaller payload keeps tool results short.

```yaml
httpConfig:
  endpoint: https://api.example.com/v1/products
  method: POST
  bodyMapping: "{ q: query, size: limit }"
  responseMapping: "results[].{name: name, price: price, inStock: available}"
```

## Redact response fields

`redact` lists top-level field names. Their values become the string `"[REDACTED]"` before `responseMapping` runs. It applies only to a 2xx response whose body is a JSON object. An error response is not redacted: its first 512 bytes appear in the error.

```yaml
httpConfig:
  endpoint: https://api.example.com/v1/customer
  method: GET
  redact: [ssn, date_of_birth]
```

With this config, the response `{"name":"Ada","ssn":"123-45-6789"}` reaches the model as `{"name":"Ada","ssn":"[REDACTED]"}`.

## Retry policy

Set `retryPolicy` on the handler. Without it a call is attempted once.

```yaml
httpConfig:
  endpoint: https://api.example.com/v1/data
  method: GET
  retryPolicy:
    maxAttempts: 3                        # includes the first attempt; 1 to 10
    initialBackoff: "200ms"
    backoffMultiplier: "2.0"
    maxBackoff: "10s"
    retryOn: [429, 500, 502, 503, 504]    # replaces the default status list
    retryOnNetworkError: true
    respectRetryAfter: true
```

Defaults, bounds and the other transports' variants are in [HTTP retry policy](/reference/core/toolregistry/#http-retry-policy). The same shape applies to `openAPIConfig`.

## Verify

Call the handler from the registry's **Test** tab, described in [Test a tool](/how-to/tools/test-tools/), and check that `result` has the shape you mapped. Then ask the agent a question that needs the tool. If the model never calls it, check that the prompt's `tools` list names it.

## Related pages

- [ToolRegistry reference](/reference/core/toolregistry/)
- [Authenticate tools](/how-to/tools/authenticate-tools/)
- [Test a tool](/how-to/tools/test-tools/)