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

# Create a gateway policy

`POST /v1/platform/gateway-policies`

Creates a gateway policy for the calling organization.

**policy_type** is one of `spend_cap`, `default_spend_cap`, or
`guard`. The shape of `config` depends on policy_type:
- `spend_cap` / `default_spend_cap`:
`{"window": "hourly"|"daily"|"weekly"|"monthly", "limit_usd": <number>}`
- `guard`:
`{"version": 1, "detect": {"pii": <bool>, "secrets": <bool>}, "timeout_seconds": <number>}`
`timeout_seconds` (optional, 0.1–600) caps guard pipeline execution time; defaults to 2s.

**subject_matchers** is a list of `{key, value}` pairs.
`key` is one of `organization_id`, `workspace_id`, `user_id`,
`api_key_id`, or `run_rule_id`. Multiple matchers AND together. A
`default_spend_cap` uses `{key, value: ""}` so the runtime
materializes a per-subject child for every distinct subject
of that kind it sees in request metadata.

**action** is currently always `block`. Spend caps reject the
request with 402 when the limit is hit; guard policies redact
matched content in-place before forwarding upstream.

**Upsert by matchers:** 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. 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_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.
  - `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, and cleared (NULL) only when an admin Create with the same matchers takes over the materialized row. Update on a child preserves the link; Delete on the parent cascade-soft-deletes every child rather than detaching them.
  - `policy_type` string
  - `priority` integer
  - `subject_matchers` GatewayPoliciesSubjectMatcher[]
    - `key` string
    - `value` string
  - `updated_at` string

## Other responses

- `400` — validation failure (bad matchers, unknown policy_type, missing required field)
- `401` — missing or invalid auth
- `403` — LLM Gateway not enabled for the organization, or caller lacks OrganizationManage
- `409` — policy name conflict
- `500` — Internal Server Error

---

[API](https://skmtc.net/langchain-ai/apis/langsmith.md) · [All operations](https://skmtc.net/langchain-ai/apis/langsmith/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/langchain-ai/langsmith/versions/a0acb3a6a101/schema)
