---
title: "Create a gateway policy"
method: POST
path: "/api/v1/platform/gateway-policies"
tags: ["gateway-policies"]
---

# Create a gateway policy

`POST /api/v1/platform/gateway-policies`

## Request

- Base URL: `https://api.smith.langchain.com`
- URL: `https://api.smith.langchain.com/api/v1/platform/gateway-policies`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Creates a gateway policy for the calling organization.

**policy_type** is one of `spend_cap`, `default_spend_cap`,
`guard`, `route_config`, `model_fallback`, `rate_limit`, or `default_rate_limit`.
The shape of `config` depends on policy_type:
- `spend_cap` / `default_spend_cap`, one limit:
`{"window": "hourly"|"daily"|"weekly"|"monthly", "limit_usd": <number>}`
- `spend_cap` / `default_spend_cap`, a limit per window:
`{"version": 2, "limits": [{"window": "hourly"|"daily"|"weekly"|"monthly", "limit_usd": <number>}]}`
- `guard`:
`{"version": 1, "detect": {"pii": <bool>, "secrets": <bool>, "custom": [{"pattern": "<regex>"}]}, "timeout_seconds": <number>, "timeout_action": "allow"|"block"}`
`timeout_seconds` (optional, 0.1–30) caps guard pipeline execution time; defaults to 2s. `timeout_action` defaults to `allow`.
`detect.custom` (optional) holds at most one Go regexp (RE2 syntax) of up to 512 bytes; matching text is redacted. Avoid capture groups: if present, only the first group is redacted, wherever that text appears.
- `route_config`:
`{"strategy": "priority_fallback", "triggers": {"status_codes": [<int>]}, "fallbacks": [{"model_configs": [{"model_config_id": "<playground-settings-uuid>"}]}]}`
`triggers` is required, with no default: `status_codes` must be a non-empty list (include 502 and 504 for upstream transport failures). `fallbacks` contains an entry whose `model_configs` are tried in priority order (1–5). `subject_matchers` must be a single `workspace_id` entry.
- `model_fallback`:
`{"strategy": "priority_fallback", "triggers": {"status_codes": [429, 502, 503, 504]}, "chain": {"selector": {"type": "provider_model", "provider": "openai", "model": "gpt-4o"}, "candidates": [{"type": "provider_model", "provider": "openai", "model": "gpt-4o-mini"}, {"type": "model_config", "model_config_id": "<playground-settings-uuid>"}]}}`
Optional `ejection: {"failure_threshold": <1-1000>, "cooldown_seconds": <1-300>}` skips a candidate for `cooldown_seconds` after it fails the chain's triggers `failure_threshold` times within `cooldown_seconds`. Failures are counted per policy and candidate, only provider failures count, and success does not reset the count. The last candidate is never skipped.
`chain.candidates` is an ordered list of 1–5 direct provider models or saved workspace model configurations. A non-empty `workspace_id` matcher is required. `provider_model` selectors are workspace-only; `alias` selectors may be narrowed by `user_id` or `api_key_id`. Provider/model selectors are unique within a workspace, while alias names are reserved across the organization and may intentionally shadow a model name.
- `rate_limit` / `default_rate_limit`:
`{"version": 1, "limits": [{"metric": "requests"|"tokens", "window": "minute"|"hour", "value": <integer>}]}`
`limits` must be non-empty; each `metric`/`window` pair may appear at most once. `value` is 1..1000000000000000.

**subject_matchers** is a list of `{key, value}` pairs. Built-in
keys are `organization_id`, `workspace_id`, `user_id`, `api_key_id`,
and `run_rule_id`. Values under the same key are ORed; distinct keys
are ANDed. A default policy uses an empty built-in matcher value so
the runtime materializes a child for each subject it sees. A
`default_spend_cap` and `default_rate_limit` may add one empty custom
metadata key to bucket each subject by the corresponding
`X-Gateway-*` request header; the materialized child stores both values.

**action** is currently always `block`. Spend caps reject the
request with 402 when the limit is hit; rate limits reject with
429 (with a `Retry-After` hint) when a limit is exceeded; guard
policies redact matched content in-place before forwarding upstream.

**Upsert by matchers:** for `spend_cap`, `default_spend_cap`,
`rate_limit`, `default_rate_limit`, and `guard`, if a policy with
the same `subject_matchers` already exists in this organization,
the existing policy is updated in place instead of a duplicate
being created. `id` is preserved. `route_config` and `model_fallback` do not upsert
by matchers — name must be unique per organization (409 on
conflict). Returns 201 either way.

## Request body

- GatewayPoliciesCreateGatewayPolicyRequest
  - `action` string
  - `config` object
  - `description` string
  - `enabled` boolean
  - `name` string
  - `policy_type` string
  - `priority` integer
  - `subject_matchers` GatewayPoliciesSubjectMatcher[]
    - `key` string
    - `value` string

## Response `201`

Created

- GatewayPoliciesGatewayPolicyRecord
  - `action` string
  - `config` object
  - `created_at` string
  - `created_by` string
  - `current_spend` GatewayPoliciesSpendUsage[]: CurrentSpend is the list of spends recorded for each of the tracked spend limit windows, used in v2 of spend_cap policy type.
    - `spend_usd` number: SpendUSD is the spend recorded in this window.
    - `window` string: Window is the spend limit period.
  - `current_spend_usd` number: CurrentSpendUSD is the spend in the policy's current window. Set for any spend_cap policy regardless of enabled state — disabled policies still surface usage so users can see what would have been counted. Nil for non-spend_cap policies or when the spend lookup failed.
  - `current_usage` GatewayPoliciesRateLimitUsage[]: CurrentUsage is the consumed units in each configured limit's current window. Set for any rate_limit policy regardless of enabled state, one entry per limit in the config. Nil for non-rate_limit policies or when the usage lookup failed.
    - `metric` 'requests' | 'tokens'
    - `value` integer: Value is the units consumed so far in the current window.
    - `window` 'minute' | 'hour'
  - `description` string
  - `enabled` boolean
  - `id` string
  - `is_system_generated` boolean
  - `name` string
  - `organization_id` string
  - `parent_policy_id` string: ParentPolicyID is set on materialized children of a default_spend_cap to the default's id. An explicit Update or a Create with the same matchers clears the link and takes ownership of the materialized row. Delete on the parent cascade-soft-deletes children still attached.
  - `policy_type` string
  - `priority` integer
  - `subject_matchers` GatewayPoliciesSubjectMatcher[]
    - `key` string
    - `value` string
  - `updated_at` string

## Other responses

- `400`: validation error
- `401`: missing or invalid auth
- `403`: LLM Gateway not enabled for the organization, or caller lacks organization:gateway:manage
- `409`: policy name conflict
- `500`: Internal Server Error

## Changes

- **2026-10-16** `1a8ee9358d81`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/langchain-ai/apis/langsmith/changes/api/v1/platform/gateway-policies/post.md)

---

[API](https://skmtc.dev/langchain-ai/apis/langsmith.md) - [All operations](https://skmtc.dev/langchain-ai/apis/langsmith/llms.txt) - [OpenAPI document](https://skmtc.dev/langchain-ai/apis/langsmith/revisions/7a01c01f75e8?raw)
