Skip to main content
NSP enforces per-API-key rate limits to prevent agent code from overwhelming the daemon and the monitored applications. The rate limiter uses a token bucket algorithm — short bursts above the limit are absorbed by the bucket’s capacity, but sustained request rates above the configured ceiling are throttled with a 429 Too Many Requests response.

Default Limits by Endpoint

Different endpoint categories carry different default limits, reflecting the relative cost of each operation.
Rate limits are tracked per API key. If you run multiple agents sharing one key, their requests all count toward the same bucket. Use a dedicated key per agent to isolate rate limits.

The 429 Response

When you exceed a rate limit, the daemon returns 429 Too Many Requests with a Retry-After header and a structured JSON body:
Always read retry_after_ms (or the Retry-After header in seconds) and wait at least that long before retrying. Sending requests immediately after a 429 wastes your token budget and prolongs the throttle window.

Retry Strategy

Use exponential backoff when handling 429 responses. This prevents a flood of retries from cascading into further throttling.
The Python SDK raises NSPRateLimitError on a 429 response. The retry_after attribute contains the wait time in seconds.

How the Python SDK Surfaces Rate Limit Errors

NSPRateLimitError is raised any time the daemon responds with 429. The exception carries the following fields:

Configuring Rate Limits in axon.toml

Adjust the defaults by editing the [rate_limit] section in axon.toml:
Changes to axon.toml take effect on daemon restart. Unlike axon_keys.json, the rate limit configuration is not hot-reloaded.

Best Practices

Use WebSocket streaming instead of polling

The /watch WebSocket stream is not rate-limited and delivers state-change events as they happen. Replace any tight GET /state polling loop with a WebSocket subscription to stay well within limits.

Batch state reads

A single GET /state call returns all state keys for an app. If your agent needs values from five fields, read them all in one request instead of five — every request counts against the same bucket.

Respect the Retry-After header

The daemon tells you exactly how long to wait. Honouring that value avoids wasting additional tokens on requests that will also be rejected.

Raise limits only for known workloads

Increase action_per_second in axon.toml only when you have profiled your agent and confirmed it genuinely needs higher throughput — lower limits reduce blast radius if agent code loops unexpectedly.