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, rate_limit, or default_rate_limit.
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_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.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.
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 or default_rate_limit 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; 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 does not upsert
by matchers — name must be unique per organization (409 on
conflict). Returns 201 either way.
Authorizations
Body
Response
Created
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.

