Limits
Values for heyidentity.dev · last updated October 2026
What the hosted service limits, how much each plan allows, and how to tell one rejection from another. Self-hosted or staging deployments can use other values.
Runtime limits per source
Every protocol endpoint limits requests per source. These limits protect the service from floods and are the same on every plan. A request over its limit is rejected with HTTP 429 and a Retry-After header.
| Endpoint | Limit per source |
|---|---|
| Authorize, end session and the pinned user page (one shared limit) | 300 per minute |
| User selection page (the page and its form post) | 600 per minute |
| Token | 600 per minute |
| Discovery | 300 per minute |
| JWKS | 300 per minute |
| Userinfo | 300 per minute |
A sign-in makes one authorize request, plus two user selection page requests when the user picker is shown. The selection page has its own limit, so one source can complete as many fresh sign-ins as its authorize limit allows, 300 per minute, with the user picker or with a single-user configuration.
What counts as a source
A source is one IPv4 address or one IPv6 /64. Clients behind a shared egress address, such as a NAT or shared CI runners, share a source and its limits.
The address is the one of the client that connects to HeyIdentity, as the edge proxy forwards it. For authorize, the user selection page, end session and the pinned user page that is the browser of the person signing in. For token, discovery, JWKS and userinfo it is the server or CI runner that calls the endpoint, so a test suite's token requests all count against the runner's address.
Token requests per client
The token endpoint also limits requests per client_id: 4000 per minute, whatever the source. It applies to a client_id sent in the request body. It is checked after the per-source limit, so a request can be rejected by either. It sits above what any tenant tier can issue in a minute, so a tenant with its own client_id reaches its tenant limit first.
Tenant tiers
Each tenant has one tier. It decides how many configurations, clients and users the tenant may hold, how large a configuration document may be, and how many sign-in and token requests the whole tenant may make.
- Unverified: a tenant an AI agent created that nobody has claimed yet.
- Free: a tenant whose owner confirmed their email address: a confirmed sign-up, or a claimed agent tenant.
- Pro: a tenant with an active Pro plan, for example through the early-adopter offer.
- Enterprise: a tenant HeyIdentity granted higher limits on request, for a fixed period; see how to ask for higher limits.
| Limit | Unverified | Free | Pro | Enterprise |
|---|---|---|---|---|
| Configurations per tenant | 1 | 5 | 20 | 50 |
| Clients per configuration | 3 | 5 | 20 | 50 |
| Users per configuration | 10 | 20 | 100 | 250 |
| Configuration document size | 32 KB | 64 KB | 256 KB | 256 KB |
| Token issuance per tenant (sustained) | 20 per minute | 120 per minute | 300 per minute | 1200 per minute |
| Token issuance burst | 20 | 120 | 600 | 2400 |
| Fresh sign-ins (sustained) | 10 per minute | 60 per minute | 150 per minute | 600 per minute |
| Session pinning | Not included | Not included | Included | Included |
| Tenant lifetime | 7 days if agent-created, 30 days for an unconfirmed sign-up | No expiry | No expiry | No expiry |
Enterprise values are the starting values of a tier HeyIdentity grants on request. Every Enterprise tenant gets the same values; they may be raised, and they are not lowered while a grant is active. Tenants created by HeyIdentity staff get the Pro limits. A configuration with one user never shows a user picker, on every plan.
What counts toward token issuance
Every authorize request and every token request counts, refresh requests included, and so does a request that is later rejected for another reason. The user selection page does not count. A fresh sign-in uses two (one authorize and one token request) and each refresh one more, so the sustained rate allows half as many fresh sign-ins. The allowance belongs to the tenant, not to a source or a client.
A tenant that has been quiet can use its whole burst at once, for example when every worker of a CI run signs in at the start. After that its allowance refills at the sustained rate, in steps of at most a second, up to the burst again.
At an item maximum
At the maximum of configurations, clients or users, the Agent API answers 400 usage_limit_exceeded naming the limit, and the owner editor disables Add with a short explanation. Items above a maximum, for example after Pro ends, keep working and stay editable. You just can't add more until you are below it.
Windows and retries
Per-source and per-client_id windows are fixed: the count starts at zero again when the window ends, not a window after your first request. The tenant's allowance refills in small steps instead.
Every runtime and Agent API rejection carries Retry-After in seconds. For a fixed window it is at most the window length, for the tenant limit at most one refill step. A client that waits that long finds the limit open again. Nothing retries a rejected sign-in for you, see running CI.
Telling rejections apart
A rejected request gets HTTP 429 and a Retry-After header. The error and the start of the error_description say which limit it was. The per-tenant rejection also carries an error_uri that links how to get more room.
| Limit | Endpoint | HTTP status | error | error_description starts with |
|---|---|---|---|---|
| Per source | Authorize, end session | 429 | slow_down |
Too many requests from this source. |
| Per source | Token | 429 | slow_down |
Too many requests from this source. |
Per client_id |
Token | 429 | slow_down |
Too many token requests for this client_id. |
| Per tenant (token issuance) | Authorize, token | 429 | slow_down, with error_uri |
Too many authorize/token requests for this tenant. |
| Per source | User selection page, pinned user page, discovery, JWKS, userinfo | 429 | None: the response has no body | None |
Agent API limits
The Agent API has its own limits. A source is defined as above.
| Limit | Value |
|---|---|
| Tenant creations per source | 10 per hour |
| Tenant creations overall | 100 per hour |
| Unclaimed tenants alive at once | 2000 |
| Calls per source | 120 per minute |
| Calls per agent token | 60 per minute |
| Active agent tokens per tenant | 10 |
| Claimed tenants per email address | 10 |
How to ask for higher limits
- An unverified tenant is claimed and its email verified: it gets the Free limits.
- A Free tenant activates Pro on its management page.
- A tenant that needs more than Pro asks for Enterprise.
Enterprise raises the tenant's total across several sources. A single source stays at the per-source limits on every plan: up to 300 per minute fresh sign-ins by its authorize limit, and 600 per minute token requests by its token limit, which is half of Enterprise's sustained rate of 1200 per minute. So one runner behind one address gains nothing from Enterprise over Pro's burst.
To ask, email support@heyidentity.dev with your tenant route id, the sign-ins and refreshes per minute you expect, and how many runners or egress addresses your tests use.
The tenant route id is shown with a Copy button at the top of your management page. It is also the part after /t/ in your authority URL.
Enterprise is granted for a fixed period. The values above are starting values: a later grant period may come with higher ones, and active grants are never lowered.
Questions
Why do I get a 429 or slow_down?
One of the limits above was used up. Compare the response with the rejections table, and wait the seconds its Retry-After header gives before you try again. A per-source rejection means the address your requests come from sent too many requests to that endpoint in the window. A per-tenant rejection means all sign-ins and token requests of the tenant did.
How do I run a large CI suite within the limits?
Nothing retries a rejected sign-in automatically. A browser sign-in that gets a 429 shows an error page, and MSAL and Microsoft.Identity.Web throw instead of waiting. So a suite that runs past its tier's allowance fails, unless it retries on Retry-After itself. How a suite gets its tokens decides which plan it fits:
| How tests get tokens | Fits |
|---|---|
| One sign-in per test user, reused for the whole run (for example Playwright storage state, or a cached token) | Free |
| One sign-in per test class or fixture | Pro, within its burst of 600 |
| A fresh sign-in or token request per test | Not recommended on any plan. From one runner it is stopped by the per-source limits, which no plan raises. |
- Cache tokens per test user. An AI agent writing a test suite should do the same instead of fetching a token per test.
- Use a configuration with a single user for CI. It never shows a user picker, on every plan, so there is no extra click and no pin to manage.
- Cache discovery and JWKS in your app under test, as a production app does.
- Remember that parallel runners behind one egress address share a source, and that the whole tenant shares its token issuance allowance. For a suite spread over several runners that needs more than Pro, see how to ask for higher limits.
Do the limits apply per source, per client or per tenant?
All three, to different things. Requests are limited per source on every protocol endpoint. Token requests are also limited per client_id. Sign-in and token requests count against the tenant's token issuance allowance, and the number of items a tenant may hold depends on its tier.
How do I get more room?
- Remove an item you no longer use.
- Claim and verify an unverified tenant: the claimed tenant gets the Free limits.
- Activate Pro. During the early-adopter offer, the owner of a verified tenant does it on the management page; see pricing.
- Ask for Enterprise limits if your suite needs more than Pro across several runners; see how to ask for higher limits.