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

# HTTP policies

> Control the HTTPS requests a Sailbox sends

An HTTP policy controls HTTPS requests from a Sailbox. A policy can:

* Add, replace, or remove request headers and query parameters
* Change a request path
* Send a request to a different HTTPS host
* Return a response without sending an HTTP request to the destination
* Add a stored credential to a request

A policy belongs to your organization. You can attach one policy to many
Sailboxes, and each Sailbox can have one policy attached at a time.

For a guided credential example, start with
[Credential injection](/sailboxes-credentials).

## Write a policy

A policy is a JSON document. Each top-level key selects a host, and each host
has an ordered list of rules.

This policy adds an API version header to HTTPS requests to
`api.example.com`:

```json theme={null}
{
  "api.example.com": {
    "rules": [
      {
        "request": {
          "set": {
            "headers": {
              "x-api-version": "2"
            }
          }
        }
      }
    ]
  }
}
```

If no host or rule matches, Sail sends the request unchanged.

### Match a host

Host keys use one of these forms:

* `api.example.com` matches that exact host.
* `*.example.com` matches any direct subdomain (one label), such as
  `api.example.com`. It does not match `example.com` or `one.two.example.com`.
* `*` matches any host not selected by a more specific entry.

Write the hostname without `https://`, a port, a path, or a leading dot. Sail
selects the most specific host entry and uses only that entry. Host entries do
not combine.

Use exact hosts when a rule adds credentials. A wildcard sends the credential
to every host it matches.

### Match a request

Add `match` to limit a rule by method, path, headers, or query parameters:

```json theme={null}
{
  "match": {
    "method": "POST",
    "path": {
      "prefix": "/v1/"
    }
  },
  "request": {
    "set": {
      "headers": {
        "x-api-version": "2"
      }
    }
  }
}
```

`method` is one HTTP method or a list of methods. Matching is exact, so write
methods in upper case, such as `GET`.

`path` and the header and query conditions below accept these matcher forms:

* A plain string matches that exact value.
* `{"equals": "/v1/models"}` is the explicit form of the same exact match.
* `{"prefix": "/v1/"}` matches values that start with that text.
* `{"one_of": ["/v1/models", "/v1/files"]}` matches any value in the list.

`headers` and `query` are lists of conditions, and every condition in the list
must hold. A condition can check a name, a value, or both, and
`"present": false` with a name requires that name to be absent:

```json theme={null}
{
  "match": {
    "headers": [{ "name": "x-debug", "present": false }],
    "query": [{ "name": "format", "value": { "one_of": ["json", "yaml"] } }]
  }
}
```

Sail checks rules from top to bottom and uses the first matching rule. A rule
without `match` covers every request that reaches it, so Sail accepts a rule
without `match` only in the last position of a host's rule list.

### Choose what a rule does

| Key       | What it does                                                                                                                    |
| --------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `request` | Changes the outgoing request's headers, query parameters, or path.                                                              |
| `forward` | Sends the request to another HTTPS host. `host` must be an exact hostname. `port` is optional and defaults to 443.              |
| `respond` | Returns a response without sending an HTTP request to the destination. `status` is required. `headers` and `body` are optional. |

A rule can use `request`, `forward`, or both. A rule that uses `respond` cannot
also use `request` or `forward`. A matching rule with none of these sends the
request unchanged.

#### Change a request

Use `request.set` to replace or create headers, query parameters, or the path.
Use `request.add` to append headers or query parameters. Use `request.remove`
to delete them.

#### Send a request to another host

Use `forward` with an exact HTTPS hostname:

```json theme={null}
{
  "forward": {
    "host": "backend.example.com"
  }
}
```

You can combine `forward` with `request` in the same rule. If that request
change adds a credential, the host you forward to receives the credential. The
request fails if Sail cannot reach that host. It is not sent to the original
host instead.

#### Return a response

Use `respond` when the Sailbox should receive a response without sending an
HTTP request to the destination:

```json theme={null}
{
  "respond": {
    "status": 403,
    "headers": {
      "content-type": "text/plain"
    },
    "body": "This request is not allowed."
  }
}
```

Do not use `respond` as a network access control. It stops this HTTP request,
but other traffic to the same host may still be possible.

#### Add a stored credential

Use `${secrets.NAME}` in a value under `request.set.headers` or
`request.set.query`. The named organization secret must exist before you create
the policy.

Those two fields are templates. Every dollar sign in them must be part of
`$$` or `${secrets.NAME}`, so write `$$` for a literal dollar sign. Any other
`$` is rejected when the policy is created. Every other string in the document
treats `$` as plain text, with one exception: an unescaped `${` is rejected
because it looks like a reference that would not be resolved. These strings
have no escape rule. `$${` is accepted, and Sail uses those exact characters.
A value that needs the exact text `${` cannot be written in these fields.

See [Credential injection](/sailboxes-credentials) for a complete example and
safety guidance.

## Create and attach a policy

Create a policy once, then attach it to each Sailbox that should use it. The
credential injection guide shows the CLI, Python, TypeScript, and Rust creation
and attachment calls.

Attaching a policy replaces the policy currently attached to that Sailbox.
Clearing it leaves the Sailbox with no policy.

An attach, replace, or clear affects HTTPS connections the Sailbox opens after
the call succeeds. Connections already open keep the previous policy until
they close. Close connections your code keeps open if the change must take
effect before the next request.

A policy document cannot change after creation. Create and attach a new policy
to change its behavior. You can rename a policy without changing its rules.

If a document is invalid, policy creation fails and the error identifies the
part of the document to fix.

Sail saves a normalized form of the document. Reading a policy back can return
a different shape from the JSON you sent, such as lowercased host names and
filled-in defaults. The behavior is the same.

For secret updates and the order for removing policies and secrets, see
[Credential injection](/sailboxes-credentials).

## Limitations

* HTTP policies apply only to HTTPS. Plain HTTP and raw TCP are unchanged.
* A policy applies to an HTTPS connection only when the client announces its
  HTTP version while connecting (a TLS feature called ALPN), which almost
  every HTTP client does. A connection without that announcement passes
  through unchanged. On an exact host entry, set `"missing_alpn": "http/1.1"`
  next to `rules` to treat such connections as HTTP/1.1. Wildcard and `*`
  entries do not accept this key.
* Request bodies cannot be matched or changed.
* Responses from a destination cannot be changed.
* A `respond` rule stops the matching HTTP request, but it does not block other
  traffic to the same host.
