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

# Networking and connectivity

> Configure URLs, rate limits, load balancer settings, and network access paths for a self-hosted Braintrust data plane.

Configure SDK endpoints, incoming request behavior, and access to external and private services.

## Client routing

### Customize the webapp URL

The SDKs guide users to `https://www.braintrust.dev` (or the `BRAINTRUST_APP_URL` variable) to view their experiments. In some
advanced configurations, you can reverse proxy traffic to the `BRAINTRUST_APP_URL` from the SDKs while pointing users to a different URL.

To do this, you can set the `BRAINTRUST_APP_PUBLIC_URL` environment variable to the URL of your webapp. By default, this variable is set to the value of `BRAINTRUST_APP_URL`, but you can customize it as you wish. This variable is *only* used to display information, so even its destination does not need to be accessible from the SDK.

> [tab] AWS
>
> Set it through the `braintrust_api_extra_env_vars` passthrough map (Terraform module v6.0.0 or later):
>
> ```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> braintrust_api_extra_env_vars = {
>   BRAINTRUST_APP_PUBLIC_URL = "https://braintrust.example.com"
> }
> ```
>
> Deployments still served by the API Lambda (before module v6.0.0, or v6.0.0 and later with `enable_ecs_api = false`) set the same variable through `service_extra_env_vars.APIHandler` instead.

> [tab] GCP / Azure
>
> Add it to `api.extraEnvVars` in your `values.yaml`:
>
> ```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> api:
>   extraEnvVars:
>     - name: BRAINTRUST_APP_PUBLIC_URL
>       value: "https://braintrust.example.com"
> ```

### Constrain SDKs to the data plane

If you're self-hosting the data plane, you can also constrain the SDKs to only communicate with your data plane. Normally, they
communicate with the control plane to:

* Get your data plane's URL
* Register and retrieve metadata (e.g. about experiments)
* Print URLs to the webapp

The data plane can proxy the endpoints that the SDKs use to communicate with the control plane, allowing your SDKs to only communicate with the data plane directly. Set the `BRAINTRUST_APP_URL` environment variable to the URL of your data plane and `BRAINTRUST_APP_PUBLIC_URL` to `https://www.braintrust.dev` (or the URL of your webapp).

> [tab] AWS
>
> ```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> braintrust_api_extra_env_vars = {
>   BRAINTRUST_APP_URL        = "https://dataplane.example.com"
>   BRAINTRUST_APP_PUBLIC_URL = "https://www.braintrust.dev"
> }
> ```

> [tab] GCP / Azure
>
> ```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> api:
>   extraEnvVars:
>     - name: BRAINTRUST_APP_URL
>       value: "https://dataplane.example.com"
>     - name: BRAINTRUST_APP_PUBLIC_URL
>       value: "https://www.braintrust.dev"
> ```

## Inbound traffic

### Set HTTPS on the API load balancer

On AWS with the ECS API, an internal Application Load Balancer (ALB) fronts the API services. CloudFront terminates TLS for inbound traffic and reaches this ALB over a private VPC origin, so the ALB does not need its own certificate in a standard deployment. By default, the ALB serves plain HTTP on port 80 using its AWS-assigned DNS name. To serve HTTPS on a custom domain instead, set both `braintrust_api_alb_certificate_arn` and `braintrust_api_alb_custom_domain` (available in Terraform module v6.0.0 or later):

```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
braintrust_api_alb_certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/abc123"
braintrust_api_alb_custom_domain   = "braintrust.internal.example.com"
```

When both are set, the ALB serves HTTPS on port 443, plain HTTP is disabled, and all API URLs use `https://<braintrust_api_alb_custom_domain>`. The certificate must cover the custom domain, and the domain must resolve to the ALB.

> [!NOTE]
>
> These two variables must both be set or both be null. Setting only one fails at plan time.

> [!WARNING]
>
> Enabling HTTPS after the ECS API exists will cause disruption: AWS will not change the protocol of a CloudFront VPC origin that is attached to a distribution, and rolling back `enable_ecs_api` does not recover it. If you enable it, you must do so during the initial apply of the [v6 upgrade](https://docs.braintrust.dev/admin/self-hosting/upgrade/v6.md). [Contact Braintrust](mailto:support@braintrust.dev) before enabling HTTPS on the ALB in an existing deployment.

### Set the HTTP keep-alive timeout

When the API server runs behind a load balancer, you may need to configure the HTTP keep-alive timeout to prevent connection resets. Load balancers typically have an idle timeout for connections, and if the API server's keep-alive timeout is shorter than the load balancer's timeout, the API server closes the connection while the load balancer still considers it open. When the load balancer tries to reuse that backend connection, it encounters a closed socket, resulting in connection reset errors and 502 responses.

The API server exposes the following environment variable to configure the keep-alive timeout:

* `TS_API_KEEP_ALIVE_TIMEOUT_SECONDS`: The HTTP keep-alive timeout in seconds. Default: `65`

The default value of 65 seconds is designed to work with most load balancers, including AWS Application Load Balancer (which has a default idle timeout of 60 seconds). However, if your load balancer has a longer idle timeout, you should set this value to match or exceed your load balancer's timeout.

For example, to match an AWS ALB configured with a 300-second idle timeout:

> [tab] AWS
>
> Set it through the `braintrust_api_extra_env_vars` passthrough map (Terraform module v6.0.0 or later). This applies to the ECS API services:
>
> ```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> braintrust_api_extra_env_vars = {
>   TS_API_KEEP_ALIVE_TIMEOUT_SECONDS = "300"
> }
> ```

> [tab] GCP / Azure
>
> Add it to `api.extraEnvVars` in your `values.yaml`:
>
> ```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> api:
>   extraEnvVars:
>     - name: TS_API_KEEP_ALIVE_TIMEOUT_SECONDS
>       value: "300"
> ```

### Set the CloudFront origin timeout

On AWS, requests are served through CloudFront, which closes a connection and returns `504 Gateway Timeout` if the origin takes too long to respond. Long-running scorers or tools invoked through `/function/invoke` can exceed the default 60-second origin read timeout. Raise it with the `cloudfront_origin_read_timeout` Terraform variable (available in Terraform module v5.3.0 or later):

```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
cloudfront_origin_read_timeout = 120
```

The value must be between 1 and 180 seconds. CloudFront caps the origin read timeout at 180 seconds, and values above 60 seconds can require an AWS Support request to raise the account quota.

### Set the CloudFront minimum TLS version

On AWS deployments that supply a custom certificate through `custom_certificate_arn`, CloudFront negotiates a minimum TLS version of `TLSv1.3_2025` with viewers. To support clients that cannot negotiate TLS 1.3, lower the floor with the `cloudfront_minimum_protocol_version` Terraform variable (available in Terraform module v6.5.2 or later):

```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
cloudfront_minimum_protocol_version = "TLSv1.2_2021"
```

Accepted values are `TLSv1`, `TLSv1_2016`, `TLSv1.1_2016`, `TLSv1.2_2018`, `TLSv1.2_2019`, `TLSv1.2_2021`, and `TLSv1.3_2025`. The setting applies to the whole distribution. Leave it unset to keep the `TLSv1.3_2025` default.

> [!NOTE]
>
> Set `cloudfront_minimum_protocol_version` only alongside `custom_certificate_arn`. Terraform rejects the configuration otherwise, because CloudFront cannot set a minimum protocol version on the default certificate.

### Set inbound request rate limits

The API server can rate-limit log ingestion, SQL queries, and function invocation. Configure each surface separately with its own environment variables for limits, window length, and enforcement.

All three surfaces behave the same way in these respects:

* **Windows**: Each limit uses a fixed window that starts when the first matching request is counted, not on a clock boundary. The counter resets after the configured number of seconds, and the next matching request starts a new window. Rejected requests still count toward the limit.
* **Enforcement**: With enforcement disabled, requests over a limit are allowed and the API server logs a warning. With enforcement enabled, they fail with HTTP 429 and a `Retry-After` header, and the response body reports the configured limit, the window length, and the requests consumed. A limit of `0` is a real zero-request limit, so with enforcement enabled every matching request is rejected.
* **Replicas**: Each limit applies across all API server replicas combined.
* **Restarts**: Rate limit configuration is read once at process start. Restart or redeploy the API services after changing any of these variables.

> [!NOTE]
>
> None of these variables has a dedicated Terraform variable or Helm value, so pass them through your deployment's environment variable map, as shown in the examples below. Variables that take `<id>=<max_requests>` pairs accept a comma-separated list of pairs.

#### Limit log ingestion

Log ingestion limits apply per organization and per project, and both are disabled by default. A project limit replaces the organization limit rather than adding to it, so a project with its own entry ignores the organization limit entirely. With no limit configured, ingestion is uncapped.

**Window and enforcement**

* `RATELIMIT_API_LOGS_ORG_WINDOW_SECS`: Window length in seconds. Default `60`. Despite the name, this also sets the window for project-based limits.
* `RATELIMIT_API_LOGS_ORG_ENFORCE`: Return HTTP 429 when a limit is exceeded. Default `false` (log a warning and allow the request). Despite the name, this also governs the enforcement of project-based limits.

**Organization limits**

* `RATELIMIT_API_LOGS_ORG`: Per-organization limits, as `<org_id>=<max_requests>` pairs. Find an organization's ID in the [organization switcher](https://docs.braintrust.dev/admin/organizations.md#find-your-organization-id).

**Project limits**

> [!NOTE]
>
> Project-scoped limits require data plane v2.2.1 or later.

* `RATELIMIT_API_LOGS_PROJECT`: Per-project limits, as `<project_id>=<max_requests>` pairs. Find a project's ID under ** Settings** > [** Project**](https://www.braintrust.dev/app/~/configuration/general).
* `RATELIMIT_API_LOGS_PROJECT_DEFAULT`: Limit for every project without an entry in `RATELIMIT_API_LOGS_PROJECT`. Set it only if you want every project capped.

> [tab] AWS
>
> Set these variables through the `braintrust_api_extra_env_vars` passthrough map (Terraform module v6.0.0 or later). For example:
>
> ```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> braintrust_api_extra_env_vars = {
>   RATELIMIT_API_LOGS_ORG             = "<org_id>=1000"
>   RATELIMIT_API_LOGS_PROJECT         = "<project_id>=500"
>   RATELIMIT_API_LOGS_ORG_WINDOW_SECS = "60"
>   RATELIMIT_API_LOGS_ORG_ENFORCE     = "true"
> }
> ```
>
> Deployments still served by the API Lambda (before module v6.0.0, or v6.0.0 and later with `enable_ecs_api = false`) set the same variables through `service_extra_env_vars.APIHandler` instead.

> [tab] GCP / Azure
>
> Add these variables to `api.extraEnvVars` in the `values.yaml` you pass to the Helm chart. For example:
>
> ```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> api:
>   extraEnvVars:
>     - name: RATELIMIT_API_LOGS_ORG
>       value: "<org_id>=1000"
>     - name: RATELIMIT_API_LOGS_PROJECT
>       value: "<project_id>=500"
>     - name: RATELIMIT_API_LOGS_ORG_WINDOW_SECS
>       value: "60"
>     - name: RATELIMIT_API_LOGS_ORG_ENFORCE
>       value: "true"
> ```

> [!WARNING]
>
> Setting a log ingestion limit to `0` with enforcement on rejects every matching logging request and stores nothing. Any spans the client does not retry are lost.

A request counts as one unit against whichever limit applies, regardless of how many spans it carries. If any organization or project referenced in the request exceeds its limit, the entire payload is rejected.

#### Limit SQL queries

SQL query limits apply per organization and per project, and both are disabled by default. A project limit adds to the organization limit rather than replacing it, so it can only tighten the effective limit. Organizations without their own entry fall back to `RATELIMIT_BTQL_DEFAULT`, and with no default configured, queries are uncapped.

Each [async query](https://docs.braintrust.dev/api-reference/query.md#async-queries) submission (`POST /btql/async`) counts as one query toward these limits. Requests to check an async query's status, fetch its results, or cancel it don't count.

**Window and enforcement**

* `RATELIMIT_BTQL_WINDOW_SECS`: Window length in seconds. Default `60`.
* `RATELIMIT_BTQL_ENFORCE`: Return HTTP 429 when a limit is exceeded. Default `false` (log a warning and allow the query).

**Organization limits**

* `RATELIMIT_BTQL_ORG`: Per-organization limits, as `<org_id>=<max_queries>` pairs. Find an organization's ID in the [organization switcher](https://docs.braintrust.dev/admin/organizations.md#find-your-organization-id).
* `RATELIMIT_BTQL_DEFAULT`: Limit for every organization without an entry in `RATELIMIT_BTQL_ORG`.
* `RATELIMIT_BTQL_DEFAULT_FUNCTIONS`: Separate default for queries against prompts and functions. Defaults to 20 times `RATELIMIT_BTQL_DEFAULT`, including when set to `-1`.

**Project limits**

> [!NOTE]
>
> Project-scoped limits require data plane v2.2.1 or later.

* `RATELIMIT_BTQL_PROJECT`: Per-project limits, as `<project_id>=<max_queries>` pairs. Setting one above the organization limit has no effect. With no organization limit configured, the project limit is the only one that applies. Find a project's ID under ** Settings** > [** Project**](https://www.braintrust.dev/app/~/configuration/general).

> [tab] AWS
>
> Set these variables through the `braintrust_api_extra_env_vars` passthrough map (Terraform module v6.0.0 or later). For example:
>
> ```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> braintrust_api_extra_env_vars = {
>   RATELIMIT_BTQL_ORG         = "<org_id>=1000"
>   RATELIMIT_BTQL_PROJECT     = "<project_id>=100"
>   RATELIMIT_BTQL_WINDOW_SECS = "60"
>   RATELIMIT_BTQL_ENFORCE     = "true"
> }
> ```
>
> Deployments still served by the API Lambda (before module v6.0.0, or v6.0.0 and later with `enable_ecs_api = false`) set the same variables through `service_extra_env_vars.APIHandler` instead.

> [tab] GCP / Azure
>
> Add these variables to `api.extraEnvVars` in the `values.yaml` you pass to the Helm chart. For example:
>
> ```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> api:
>   extraEnvVars:
>     - name: RATELIMIT_BTQL_ORG
>       value: "<org_id>=1000"
>     - name: RATELIMIT_BTQL_PROJECT
>       value: "<project_id>=100"
>     - name: RATELIMIT_BTQL_WINDOW_SECS
>       value: "60"
>     - name: RATELIMIT_BTQL_ENFORCE
>       value: "true"
> ```

A query counts once against the organization limit and once against each project it reads, so a query spanning several projects must stay under every limit it touches.

> [!NOTE]
>
> These limits apply to queries from the API, the SDKs, and the MCP server. Queries issued from the Braintrust UI are exempt.

#### Limit function invocation

Invocation limits cover a project's prompts, scorers, tools, and other custom code functions. They are project-scoped, and there is no organization-scoped limit. Two independent limits apply: a per-project limit that is disabled by default, and a per-function cap that is on by default with a fixed 10-second window and always returns HTTP 429.

**Window and enforcement**

* `RATELIMIT_INVOKE_WINDOW_SECS`: Window length in seconds for the project limits. Default `10`. It does not affect the per-function cap.
* `RATELIMIT_INVOKE_ENFORCE`: Return HTTP 429 when a project limit is exceeded. Default `false` (log a warning and allow the invocation). It does not affect the per-function cap.

**Project limits**

> [!NOTE]
>
> Project-scoped limits require data plane v2.2.1 or later.

* `RATELIMIT_INVOKE_PROJECT`: Per-project limits, as `<project_id>=<max_invocations>` pairs. The count covers every function in the project, across all API keys. Find a project's ID under ** Settings** > [** Project**](https://www.braintrust.dev/app/~/configuration/general).
* `RATELIMIT_INVOKE_PROJECT_DEFAULT`: Limit for every project without an entry in `RATELIMIT_INVOKE_PROJECT`. Set it only if you want every project capped.

**Per-function limit**

* `INVOKE_RATE_LIMIT_PER_10S`: Maximum invocations per function, per API key, in a 10-second window. Default `10000`. The count is per function, not per project.
* `ENABLE_INVOKE_RATE_LIMIT`: Whether invocation rate limiting runs at all. Default `true`. Setting it to `false` turns off the per-function cap and the project limits.

> [tab] AWS
>
> Set these variables through the `braintrust_api_extra_env_vars` passthrough map (Terraform module v6.0.0 or later). For example:
>
> ```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> braintrust_api_extra_env_vars = {
>   RATELIMIT_INVOKE_PROJECT     = "<project_id>=100"
>   RATELIMIT_INVOKE_WINDOW_SECS = "10"
>   RATELIMIT_INVOKE_ENFORCE     = "true"
>   INVOKE_RATE_LIMIT_PER_10S    = "5000"
> }
> ```
>
> Deployments still served by the API Lambda (before module v6.0.0, or v6.0.0 and later with `enable_ecs_api = false`) set the same variables through `service_extra_env_vars.APIHandler` instead.

> [tab] GCP / Azure
>
> Add these variables to `api.extraEnvVars` in the `values.yaml` you pass to the Helm chart. For example:
>
> ```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> api:
>   extraEnvVars:
>     - name: RATELIMIT_INVOKE_PROJECT
>       value: "<project_id>=100"
>     - name: RATELIMIT_INVOKE_WINDOW_SECS
>       value: "10"
>     - name: RATELIMIT_INVOKE_ENFORCE
>       value: "true"
>     - name: INVOKE_RATE_LIMIT_PER_10S
>       value: "5000"
> ```

> [!NOTE]
>
> Preprocessors are exempt from invocation rate limits.

## Outbound traffic

### Secure outbound requests

The data plane makes outbound requests both to Braintrust and to URLs you or your users supply, such as webhooks, remote scorers, and integrations.

**Allow traffic to Braintrust through your firewall**

If you restrict outbound network traffic, allow the data plane to reach Braintrust at:

```
www.braintrust.dev
braintrust.dev
gateway.braintrust.dev
pulse.braintrust.dev
```

`gateway.braintrust.dev` is the Braintrust-hosted Gateway. Two kinds of request go there:

* **Built-in model requests.** Braintrust serves [built-in models](https://docs.braintrust.dev/admin/ai-providers.md#manage-built-in-models) itself, so requests for them always go to the hosted Gateway. Self-hosted organizations have built-in models off by default and opt in explicitly, and [Topics](https://docs.braintrust.dev/observe/topics.md) requires them.
* **LLM calls from user-authored code**, such as custom scorers and tools, on AWS deployments that run the API on [ECS](https://docs.braintrust.dev/admin/self-hosting/upgrade/v6.md) (`enable_ecs_api = true`) with Terraform module v6.4.0 or earlier. Module v6.5.0 and later sends these to the deployment's own AI proxy instead, so that traffic stays in your AWS account.

`pulse.braintrust.dev` receives the [telemetry](https://docs.braintrust.dev/admin/self-hosting/configure/telemetry.md) your data plane sends to Braintrust.

This is firewall guidance. The data plane does not enforce a destination allowlist itself.

**Block requests to internal addresses**

To stop user-supplied URLs from reaching private or reserved IP addresses (server-side request forgery), configure URL validation. See [Configure URL security](https://docs.braintrust.dev/admin/self-hosting/configure/security.md#configure-url-security).

**Trust a private certificate authority**

If the internal services your custom scorers and tools call present certificates signed by a private or enterprise certificate authority, supply the CA bundle so those requests validate. See [Configure a custom CA bundle](https://docs.braintrust.dev/admin/self-hosting/configure/security.md#configure-a-custom-ca-bundle).

### Set outbound request rate limits

The Braintrust API server can rate-limit the outbound requests it makes to external domains, such as `BRAINTRUST_APP_URL`. Rate limiting prevents unintentionally overloading an external domain, which might otherwise block the API server's IP in response. It is disabled by default. When enabled, requests are counted per API auth token per destination domain within a rolling window.

* `OUTBOUND_RATE_LIMIT_MAX_REQUESTS`: The maximum number of requests per window. Default `0`, which disables rate limiting. Set a value greater than `0` to enable it.
* `OUTBOUND_RATE_LIMIT_WINDOW_MINUTES`: The window length in minutes before the count resets. Default `1`.

> [tab] AWS
>
> Use the dedicated variables (Terraform module v1.0.0 or later):
>
> ```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> outbound_rate_limit_max_requests   = 100
> outbound_rate_limit_window_minutes = 1
> ```

> [tab] GCP / Azure
>
> Set the environment variables through `api.extraEnvVars`:
>
> ```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> api:
>   extraEnvVars:
>     - name: OUTBOUND_RATE_LIMIT_MAX_REQUESTS
>       value: "100"
>     - name: OUTBOUND_RATE_LIMIT_WINDOW_MINUTES
>       value: "1"
> ```

### Connect to internal resources over VPC

On AWS, to connect Braintrust's VPC to other internal resources (like an LLM Gateway), use one of the following approaches:

* Create a VPC Endpoint Service for your internal resource, then create a VPC Interface Endpoint inside the Braintrust "Quarantine" VPC.
* Set up VPC peering with the Braintrust "Quarantine" VPC.

### AWS service VPC endpoints

The module creates AWS service VPC endpoints in VPCs it manages. Interface endpoints span all three private subnets and share a security group that allows HTTPS (TCP 443) from the VPC CIDR. Interface endpoint charges apply.

| Service | Type | Created when |
| - | - | - |
| S3 | Gateway | Always, in both main and quarantine VPCs |
| SSM | Interface | Main VPC with `enable_brainstore_ec2_ssm = true` (default `false`) and `create_ssm_vpc_endpoints = true` (default `true`) |
| Secrets Manager | Interface | Main VPC with `create_secrets_manager_vpc_endpoint = true` (default `true`) |

The SSM and Secrets Manager variables have no effect when `create_vpc = false`. The module doesn't create interface endpoints in the quarantine VPC or in VPCs you supply.

> [accordion] Provide your own SSM connectivity
>
> On Terraform module v6.9.0 and later, you can keep Brainstore SSM access but skip the module's three SSM endpoints (`ssm`, `ssmmessages`, and `ec2messages`):
>
> ```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> enable_brainstore_ec2_ssm = true
> create_ssm_vpc_endpoints  = false
> ```
>
> Brainstore's SSM IAM permissions don't change. Provide reachable endpoints, including DNS and security groups, or outbound HTTPS access to SSM.
>
> > [!WARNING]
> >
> > On an existing deployment, setting `create_ssm_vpc_endpoints = false` removes the module-managed SSM endpoints. Set up your replacement connectivity first so Brainstore SSM sessions keep working.

> [accordion] Opt out of the Secrets Manager endpoint
>
> On Terraform module v6.8.1 and later, the module creates a Secrets Manager endpoint by default in a module-managed main VPC, and upgrading an existing module-managed VPC adds it. Private DNS redirects the standard regional Secrets Manager hostname through the endpoint, so existing SDK and CLI calls use it without URL changes. To skip it:
>
> ```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> create_secrets_manager_vpc_endpoint = false
> ```

## Braintrust Gateway

To deploy the Gateway, configure its API endpoint, or route quarantine traffic through PrivateLink, see [Self-host the Braintrust Gateway](https://docs.braintrust.dev/admin/self-hosting/configure/gateway.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.