APIRate limits

Update rate limit rule

Update an existing rate limit rule.

PATCH
/rate-limits/rules/{rule_id}

Update an existing rate limit rule.

Authorization

ApiKeyAuth
headerAuthorizationBearer <token>

Bearer token authentication. Send an API key (a saai_api_-prefixed token) as Authorization: Bearer <token>.

Required permission

manage_rate_limits

Path Parameters

rule_id*string
Formatuuid

Request Body

application/json
  1. body

Fields that may be changed on an existing rate limit rule.

name?string

Short label for the rule, shown in the rule list.

description?|

Optional note explaining what the rule protects against.

status?RateLimitRuleStatus

Whether a rate limit rule is in effect.

Value in"active""disabled"
scope?

What a rule matches.

key_by?array<>

What a rule counts its budget per. Always includes org; add dimensions to subdivide that org-wide budget further, e.g. ["org", "user", "tool"] for a per-user-per-tool budget. Order does not matter — the list is canonicalised — but it must include org and be free of duplicates.

Items1 <= items
limit?integer

Calls allowed per window.

Formatint32
Range1 <= value
window_seconds?integer

Length of the window in seconds. Capped at one hour, the lifetime of the bucket that tracks it.

Formatint32
Range1 <= value <= 3600
burst?integer

How many calls may arrive at once before the rate applies. Also sets the granularity at which budget is released: each window admits max(burst, ceil(limit * min(1 minute, window_seconds) / window_seconds)) calls, and the window is however long that many calls take at the configured rate, never shorter than min(1 minute, window_seconds) — e.g. 1000/hour with no burst set derives a 61.2-second window admitting 17 calls, which is exactly 1000/hour. Defaults to 1. Must be at most limit.

Formatint32
Range0 <= value
action?RateLimitAction

What happens to a call once a rule's budget is spent.

Value in"deny""log_only"

Response Body

The request has succeeded.

application/json
  1. response

A throughput limit on MCP tool calls. Every rule whose scope matches a call must have budget left, so rules compose rather than override one another — an org-wide ceiling and a tighter per-user one are both enforced. Counters live in each gateway process by default, so with several replicas the effective ceiling is the configured limit times the replica count; a deployment can instead share one counter across every process through NATS.

id*string
Formatuuid
name*string

Short label for the rule, shown in the rule list.

description?|

Optional note explaining what the rule protects against.

status?RateLimitRuleStatus

Whether a rate limit rule is in effect.

Value in"active""disabled"
scope*

What a rule matches.

key_by*array<>

What a rule counts its budget per. Always includes org; add dimensions to subdivide that org-wide budget further, e.g. ["org", "user", "tool"] for a per-user-per-tool budget. Order does not matter — the list is canonicalised — but it must include org and be free of duplicates.

Items1 <= items
limit*integer

Calls allowed per window.

Formatint32
Range1 <= value
window_seconds*integer

Length of the window in seconds. Capped at one hour, the lifetime of the bucket that tracks it.

Formatint32
Range1 <= value <= 3600
burst?integer

How many calls may arrive at once before the rate applies. Also sets the granularity at which budget is released: each window admits max(burst, ceil(limit * min(1 minute, window_seconds) / window_seconds)) calls, and the window is however long that many calls take at the configured rate, never shorter than min(1 minute, window_seconds) — e.g. 1000/hour with no burst set derives a 61.2-second window admitting 17 calls, which is exactly 1000/hour. Defaults to 1. Must be at most limit.

Formatint32
Range0 <= value
action?RateLimitAction

What happens to a call once a rule's budget is spent.

Value in"deny""log_only"
created_at*string
Formatdate-time
updated_at*string
Formatdate-time
curl -X PATCH "https://example.com/rate-limits/rules/497f6eca-6276-4993-bfeb-53cbbbba6f08" \  -H "Content-Type: application/json" \  -d '{}'
{  "id": null,  "name": "string",  "description": "string",  "status": "active",  "scope": {    "type": "mcp_tool_call",    "mcp_ids": [      "c2c9208c-a7ac-41cc-84f1-8c1caec92987"    ],    "agent_slugs": [      "string"    ],    "agent_instance_ids": [      "bc3f18ff-0dcd-4cc7-8f61-6ca61814f10b"    ],    "user_ids": [      "2d98503d-4ab4-41bd-8fc6-78cc006fd2db"    ],    "groups": [      "string"    ],    "agent_slug_tag_ids": [      "e428595a-d9dd-4887-8327-2d9cad5b7425"    ],    "mcp_tag_ids": [      "17d4a46c-d971-4171-9a66-88ec59ce6eeb"    ],    "tool_tag_ids": [      "41068329-9b4f-4cc3-b249-3ec2a7a2cee8"    ],    "tool_patterns": [      "string"    ],    "condition": "string",    "condition_description": "string"  },  "key_by": [    "org"  ],  "limit": 1,  "window_seconds": 1,  "burst": 0,  "action": "deny",  "created_at": "2019-08-24T14:15:22Z",  "updated_at": "2019-08-24T14:15:22Z"}