Create a gateway policy
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>}, "timeout_seconds": <number>, "timeout_action": "allow"|"block"}timeout_seconds(optional, 0.1–30) caps guard pipeline execution time; defaults to 2s.timeout_actiondefaults toallow.route_config:{"strategy": "priority_fallback", "triggers": {"status_codes": [<int>]}, "fallbacks": [{"model_configs": [{"model_config_id": "<playground-settings-uuid>"}]}]}triggersis required, with no default:status_codesmust be a non-empty list (include 502 and 504 for upstream transport failures).fallbackscontains an entry whosemodel_configsare tried in priority order (1–5).subject_matchersmust be a singleworkspace_identry.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>"}]}}chain.candidatesis an ordered list of 1–5 direct provider models or saved workspace model configurations. A non-emptyworkspace_idmatcher is required.provider_modelselectors are workspace-only;aliasselectors may be narrowed byuser_idorapi_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>}]}limitsmust be non-empty; eachmetric/windowpair may appear at most once.valueis 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.
Authorizations
Body
Response
Created
CurrentSpend is the list of spends recorded for each of the tracked spend limit windows, used in v2 of spend_cap policy type.
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.
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.
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.

